Docstoc

Ruby on Rails Short Course Just Enough Ruby

Document Sample
Ruby on Rails Short Course Just Enough Ruby Powered By Docstoc
					      UC Berkeley




    Intro. to Ruby
   & Intro. to Rails
  CS 98-10/CS 198-10
Web 2.0 Programming Using
      Ruby on Rails
          Armando Fox
                        Administrivia
•   5um signup!!
•   Lab 0
•   Self-diagnostic quiz on web page
•   Hack sessions: Th 4-5, Fri 1-2
    – place, staffing TBA on webpage
• Books
    – more or less required: Agile Web
      Development with Rails, 1st or 2nd ed.
    – Programming Ruby (free, online at
      rubycentral.org/book)
    – or The Ruby Way by Fulton
• Online resources coming soon
       CS61A Keywords of the Day

• Symbol

• Binding
                                   Review: MVC
•   Goal: separate organization of data (model) from UI & presentation (view)
    by introducing controller
     – mediates user actions requesting access to data
     – presents data for rendering by the view
•   Web apps are “sort of” MVC by design



                                                             • Read data
      • User actions                                         • Update data
                                         (Ruby) code
                                     .rb Controller
      • Directives for
      rendering data

                     .rhtml template                SQL table +
                            View                       Model
                     (or .rjs, .rxml...)             Ruby class


                               • Data provided to
                               views
             Review: CRUD in SQL
• 4 basic operations on a table row: Create, Read,
  Update attributes, Destroy
INSERT INTO students
  (last_name, ucb_sid, degree_expected)
  VALUES (“Fox”, 99999, “1998-12-
  15”),           (“Bodik”, 88888, “2009-06-05”)
SELECT * FROM students
  WHERE (degree_expected < “2000-01-01”)
UPDATE students
  SET degree_expected=“2008-06-05”
  WHERE last_name=“Bodik”)
DELETE FROM students WHERE ucb_sid=99999
                            Review: C/C
If data model is called Student:
• model (Ruby class) is
   app/models/student.rb
• SQL table is students
   – table row = object instance
   – columns = object attribute                     QuickTime™ and a

• controller methods live in
                                          TIFF (Un compressed) decompres
                                             are neede d to see this picture.

  app/controllers/student_controller.rb
• views are app/views/student/*.rhtml
         Review: C/C & scaffolding
• Model Student implies...
  – class StudentsController in
    students_controller.rb
  – views in app/view/students/, ....
  – table students, primary key id, column names
    match Student class’s attributes
• 2 ways to scaffold your controller & views
  – metaprogramming makes it happen
                        While we’re on SQL...
                     what’s a primary key anyway?
   • Column whose value must be unique for every table row
         – Why not just use (e.g.) last name or SID#?
   • SQL AUTO_INCREMENT function makes it easy to
     specify an integer primary key
   • If using migrations to create tables (recommended),
     Rails takes care of creating an autoincrement primary
     key field called ID
                                      class CreateStudents<ActiveRecord::Migration
CREATE TABLE students (               def self.up
  id INT NOT NULL AUTO_INCREMENT,      create_table :students do |tbl|
  last_name VARCHAR(255),               tbl.column :last_name, :string
  first_name VARCHAR(255),              tbl.column :first_name, :string
  ucb_sid INT(11) DEFAULT 9999          tbl.column :ucb_sid, :integer,
);                                         :null=>false, :default=>9999
                                       end
                                      end
                                       def self.down
                                        drop_table :students
                                       end
                                      end
             Using ri and irb from the
                       shell
• Ruby is interpreted (for now)
• irb is an interactive Ruby interpreter
   – follow along with the examples!
• ri (Ruby info) is like man
   – ri Comparable
   – ri gsub
   – ri String#gsub
• Note, need to be in a shell that has PATH and
  environment variables set correctly
• See www.ruby-doc.org for more good
  documents
              Ruby’s Distinguishing Syntax
                    Characteristics
• Syntax features
    – Whitespace is not significant (unlike Python)
    – Statements separated by semicolons or carriage
      returns
    – Statement can span a newline*
    – Parentheses can often be omitted*
        * when unambiguous to parser; use caution!!

 raise "D'oh!" unless valid(arg)
 raise "D'oh!" unless
   valid(arg)
 raise "D'oh!"
   unless valid(arg)
• Advice from your elders: use a good text editor
                 Naming conventions
• ClassNames
  class NewRubyProgrammer ... end
• method_names and variable_names
  def learn_conventions ... end
• predicate_like_methods?
  def is_faculty_member? ... end
• dangerous_methods!
  def brainwash_with_ruby! ... end
• :symbols
  favorite_framework = :rails
• SOME_CONSTANTS or OtherConstants
  – result in warning if reassigned after init
              Everything is an object; (almost)
                everything is a method call
• Everything is an object
   – Even integers (try 57.methods)
   – Even nil (try nil.respond_to?(:to_s))
• (almost) every “operator” is really a method call
   – my_str.length => my_str.send(:length)
   – mymethod(“foo”) =>
     self.send(:mymethod, “foo”)
   – 1 + 2 => 1.send(:+, 2)
   – arr[4] => arr.send(:[], 4)
   – arr[3] = “foo” => arr.send(:[]=, 3, “foo”)
   – if (x == 3) => if (x.send(:==, 3))
• in particular, things like “implicit conversion” on
  comparison are done by the class methods, not in the
  language (unlike, e.g., Perl)
                        Variables & Methods
• Variables have no type; objects do
   – variables spring into existence on first assignment
• nil,false are Boolean false; everything else true
• Everything* is passed-by-reference
   – can use clone method to effect pass-by-value
   *except Fixnums...

• Defining methods
def foo(x); [x,x+1]; end

def foo(x)
  [x,x+1]
end

def foo(x)
  return [x,x+1]
end
                                       Arrays
x = [3, 'a', "third", :blah, :last]
x[0] => 3
x[-1] => :last
x[-2] => :blah
x[-3..-1] => ["third", :blah, :last]
y = [1,2]
y += [3,4] => [1,2,3,4]
y << 5 => [1,2,3,4,5]
y << [6,7] => [1,2,3,4,5,[6,7]]

• Note! These are nearly all instance methods of
  Array—not language operators!
                           Hashes
h = {"key" => 1, :value => "foo" }
h.has_key?("key") => true
h["not a key"] => nil (not an error!)
h.delete(:value) => {"key" => 1 }
h.merge( {:key2 => "3", "hi" => :blah} )
  => {"key"=> 1, "key2" => 3, “hi” => :blah}
• Ruby & Rails idioms
  – omitting braces when a function takes a hash as its
    last argument
  – omitting parens around function arguments
link_to "Edit student", :controller=>'students',
  :action=>'edit'
link_to("Edit student", {:controller=>'students',
  :action=>'edit'})
• Warning! if ambiguous parse...better safe than
  sorry!
                    Classes & Methods
# Methods for MyBank.com
class Account
  @@bank_name = "MyBank.com"
  # constructor is always called initialize
  def initialize(starting_balance=0)
    @balance = starting_balance
  end
  # instance methods
  def balance
    @balance
  end
  def deposit(amount)
    @balance += amount
  end
  def withdraw(amount)
    @balance -= amount
  end
  # A class method
  def self.bank_name
    @@bank_name
  end
end
               Instance methods, not
                 instance variables
• Let’s try a few...
my_account.@balance
my_account.balance
my_account.balance = 100
@@bank_name
other_account = Account.new(0)
other_account.bank_name
• ...got it?
       Instance variables: shortcut
class Foo
def initialize(bar,baz)
  @bar,@baz=bar,baz
end
def bar ; @bar ; end
def baz ; @baz; end
def bar=(newbar) ; @bar=newbar ; end
def baz=(newbaz) ; @baz=newbaz; end
end
       Instance variables: shortcut
class Foo
def initialize(bar,baz)
  @bar,@baz=bar,baz
end

attr_accessor :bar, :baz


end
                       REMEMBER!
• a.b means: call method b on object a
   – a is the receiver to which you send the method call,
     assuming a will respond to that method
does not mean: b is an instance variable of a
does not mean: a is some kind of structure of
  which b is a member

 Understanding this distinction will save you from
            much grief and confusion
        There are (almost) no Loops
• “Objects manage their own traversal”
• (1..10).each {|x| ... }
  => range traversal
• my_array.each {|elt| ... }
  => array traversal
• hsh.each_key {|key| ... }
  hsh.each_pair {|key,val| .. }
  => hash traversal
• 10.times {...} => iterator of arity zero
• 10.times do    ...   end
  {...} is a synonym for do...end
               What is “duck typing”?
• Ruby type = set of values
  + set of operations
• A ruby module defines...                        QuickTime™ and a
                                         TIFF (Uncompressed) decompre ssor
                                            are neede d to see this picture.



   – a collection of behaviors
   – that depend only on the
     presence of one or more
     specific existing behaviors
• i.e.: If it looks like a duck and walks like a duck
  => it responds to the same methods as a duck.
• Note, a module ≠ a class
   – but module methods can get mixed in to classes
         Mix-in example: Comparable
• Define <=> method for your class
• include Comparable
  – methods in Comparable assume that objects of target
    class (into which you’re includeing) respond to <=>
  – doesn’t actually matter what the class is!
• Get < <= => > == between? for free
  – and, your class can now be sorted (by mixing in
    Enumerable...what do you suppose it assumes?)
  – Enumerable also provides all?, any?, collect, find, include?,
    inject, map, partition, ....
             Hashes and function calls
• Immediate hash (any object can be a key, any object can
  be an attribute)
   my_hsh = {:foo => 1, "x" => nil, 3 => ['a',4]}
   my_hsh[:nonexistent_key] returns nil
• Parens can be omitted from function calls if parsing is
  unambiguous
   x = foo(3, "no")  x = foo 3, "no"
• Braces can be omitted from hash if parsing is
  unambiguous
   x = foo( {:a=>1,:b=>2})  x = foo(:a=>1,:b=>2)
   – easy way to do keyword arguments
   – Caveat: passing immediates to a function that accepts multiple
     hashes as its arguments
              Summary: Ruby’s
           Distinguishing Features
• Object-oriented with single inheritance
  – everything is an object
  – almost everything is a method call
  – Modules play a role similar to Java’s
    interfaces and enable “duck typing”
• Dynamically typed
  – Objects have types; variables don’t
  – very few operators in the language; most are
    defined as instance methods on objects
• Idiomatically, {} and () sometimes optional
          Active Record: what is it?
• A class library that provides an object-
  relational model over a plain old RDBMS
• Deal with objects & attributes rather than
  rows & columns
  – SELECT result rows  enumerable collection
  – (later) object graph  join query
         More on Student Example
• object attributes are “just” instance
  methods (a la attr_accessor)
  – so can already say stu.last_name,
    stu.ucb_sid, etc.
  – what line in what file makes this happen?
• ActiveRecord accessors/mutators
  – default attr_accessor for each table column
  – perform type-casting as needed
  – can be overridden, virtualized, etc.
Example: a short tour
  Predicate-like method
  names often end with
     question mark                     self (like Java this) not
                                      strictly necessary here




                          Some useful class
                          methods of Date

                               Interpolation of
                           expressions into strings
        Virtual attributes example:
           simple authentication
• Assume we have a table customers with
  columns salt and hashed_password...
                      Defines the receiver method
                             for password=



                               Why do we want to use self here?




                    Where’s the accessor for
                          password?
                    Constructors
• Method named initialize, but invoked as new
• (at least) 3 ways to call it...
                         New != Create
• Call s.save to write the object to the database
   s.create(args)  s.new(args); s.save
   s.update_attributes(hash) can be used to update attributes in
     place
   s.new_record? is true iff no underlying database row corresponds
     to s
• save does right thing in SQL (INSERT or UPDATE)
• Convention over configuration:
   – if id column present, assumes primary key
   – if updated_at/created_at columns in table, automatically are
     set to update/creation timestamp
                find()  SQL SELECT
# To find an arbitrary single record:
s = Student.find(:first) # returns a Student instance
# To find all records:
students = Student.find(:all) # returns enumerable!

# find by 'id' primary key (Note! throws RecordNotFound)
book = Book.find(1235)
# Find a whole bunch of things
ids_array = get_list_of_ids_from_somewhere()
students = Student.find(ids_array)

# To find by column values:
armando = Student.find_by_last_name('Fox') # may return nil
a_local_grad =
   Student.find_by_city_and_degree_expected('Berkeley',
   Date.parse('June 15,2007')

# To find only a few, and sort by an attribute
many_localgrads =
   Student.find_all_by_city_and_degree_expected('Berkeley',
   Date.parse('June 15,2007'),:limit=>30,:order=>:last_name)
                     Find by conditions
 • Use ? for values from parameters. Rails will sanitize the
 SQL and prevent any SQL injection
    • You will want to learn some minimal SQL syntax




You can also specify ordering and use arbitrary SQL operators:

 # Using SQL conditions
 books = Book.find(:all,
    :conditions => [‘pub_date between ? and ?’,
    params[:start_date], params[:end_date]],
   :order => ‘pub_date DESC’)
                     Find by conditions
• Use ? to substitute in condition values
   – not mandatory, but a good idea!




• You can include other SQL functionality
# Using SQL conditions
books = Book.find(:all,
   :conditions => [‘pub_date between ? and ?’,
   params[:start_date], params[:end_date]],
  :order => ‘pub_date DESC’)

• You can roll your own
s = Student.find_by_sql("SELECT * FROM students ...")
                        Advanced Find
You can also specify limits and offsets, and oh so much more
 books = Book.find(:all,
    :conditions => [‘pub_date between ? and ?’,
        params[:start_date], params[:end_date]],
    :limit => 10, :offset => params[:page].to_i * 10)


 • :lock - Holds lock on the records (default: share lock)
 • :select - Specifies columns for SELECT (default *)
 • :group - (used with select) to group
 • :readonly - load as read-only (object can’t be saved)
 • :include - Prefetches joined tables (try :include first;
   more about this in Section 4)
 • Note: use SQL-specific features at your own risk....
                       Caveat!
• The result of a find-all operation mixes in
  Enumerable
• Enumerable defines methods find and
  find_all
• Not to be confused with
  ActiveRecord::Base#find!
• Caveats for using self.
• => local variable, method, methodmissing
• so need self. even for mutators
• activerecord accessors/setters are lazy &
  memoized
• dymamic finders are never memoized!
                            Action View
• A template for rendering views of the model that allows
  some code embedding
   – commonly RHTML; also RXML, HAML, RJS
   – note...too much code breaks MVC separation
   – convention: views for model foo are in app/views/foo/
• “Helper methods” for interacting with models
   – model valuesHTML elements (e.g. menus)
   – HTML form inputassignment to model objects
• DRY (Don’t Repeat Yourself) support
   – Layouts capture common page content at application level,
     model level, etc. (app/views/layouts/)
   – Partials capture reusable/parameterizable view patterns
           Helper Methods for Input &
                    Output
• Review: we saw a simple view already...
   – Anatomy: <% code %> <%= output %>
• But these form tags are generic...what about model-
  specific form tags?
• In the RHTML template:
<%= text_field 'student', 'last_name'       %>
• In HTML delivered to browser:
<input id="student_last_name"
  name="student[last_name]" size="30" type="text"
  value="Fox" />
• What happened? For that we have to look at partial.
                   Action Controller
• Each incoming request instantiates a new
  Controller object with its own instance variables
  – Routing (Sec. 4) determines which method to call
  – Parameter unmarshaling (from URL or form sub.) into
    params[] hash
    ...well, not really a hash...but responds to [], []=
• Controller methods set up instance variables
  – these will be visible to the view
  – controller has access to model’s class methods;
    idiomatically, often begins with Model.find(...)
• Let’s see some examples...
                   Then we render...
• Once logic is done, render the view




  – exactly one render permitted from controller method
    (1 HTTP request  1 response)
• Convention over configuration: implicit render
  – if no other render specified explicitly in action method
  – looks for template matching controller method name
    and renders with default layouts (model, app)
            What about those model-
            specific form elements?
• Recall:
  <input type="text" id="student_last_name"
  name="student[last_name]"/>
• Related form elements for student attributes will
  be named student[attr ]
  – marshalled into params as
    params[:student][:last_name],
    params[:student][:degree_expected], etc.
  – i.e, params[:student] is a hash :last_name=>string,
    :degree_expected=>date, etc.
  – and can be assigned directly to model object instance
  – helpers for dates and other “complex” types...magic
            What else can happen?
• redirect_to allows falling through to
 different action without first rendering
  – fallthrough action will call render instead
  – works using HTTP 302 Found mechanism,
    i.e. separate browser roundtrip
• example: create method
  – success: redirect to list action
  – fail: render the new action (without
    redirect)...why?
                  The Session Hash
• Problem: HTTP is stateless (every request
  totally independent). How to synthesize a
  session (sequence of related actions) by one
  user?
• Rails answer: session[] is a magic persistent
  hash available to controller
    Actually, it’s not really a hash, but it quacks like one
  – Managed at dispatch level using cookies
  – You can keep full-blown objects there, or just id’s
    (primary keys) of database records
  – Deploy-time flag lets sessions be stored in filesystem,
    DB table, or distributed in-memory hash table
                                   The Flash
• Problem: I’m about to redirect_to
  somewhere, but want to display a notice
  to the user
• yet that will be a different controller
  instance with all new instance variables
  Rails answer: flash[]
   – contents are passed to the next action,
     then cleared
   – to this action: flash.now[:notice]
   – visible to views as well as controller




• Strictly speaking, could use session & clear it out yourself
                           Summary
• ActiveRecord provides (somewhat-)database-
  independent object model over RDBMS
• ActionView supports display & input of model
  objects
  – facilitates reuse of templates via layouts & partials
• ActionController dispatches user actions,
  manipulates models, sets up variables for views
  – declarative specifications capture common patterns
    for checking predicates before executing handlers
                         Lab 1
• Create a simple 1-model RoR app with
  basic CRUD MVC
  – Create database
  – Create the table using migrations
  – Create scaffolding using generator
• Find and fix a bug in the code provided to
  you :-o
• Hack sessions, forums will help

				
DOCUMENT INFO
Shared By:
Categories:
Tags:
Stats:
views:9
posted:2/21/2012
language:Latin
pages:47