0% found this document useful (0 votes)
40 views55 pages

Ruby On Rails: Slides Adapted From CS 198 Slides With The Gracious Permission of Armando Fox and Will Sobel

This document provides an overview and agenda for a presentation on Ruby on Rails. It begins with a brief history of web development, from Web 1.0 where every user interaction required a full page reload, to Web 2.0 where JavaScript allows for asynchronous interactions. Ruby on Rails is then introduced as a web application framework that embraces the model-view-controller pattern to separate application data, presentation, and user interaction logic. The remainder of the agenda gives a high-level overview of Ruby, the programming language Rails is built on, and demonstrates basic Rails concepts like ActiveRecord and scaffolding to quickly generate the necessary files for a sample student data management application.

Uploaded by

raw.junk
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
40 views55 pages

Ruby On Rails: Slides Adapted From CS 198 Slides With The Gracious Permission of Armando Fox and Will Sobel

This document provides an overview and agenda for a presentation on Ruby on Rails. It begins with a brief history of web development, from Web 1.0 where every user interaction required a full page reload, to Web 2.0 where JavaScript allows for asynchronous interactions. Ruby on Rails is then introduced as a web application framework that embraces the model-view-controller pattern to separate application data, presentation, and user interaction logic. The remainder of the agenda gives a high-level overview of Ruby, the programming language Rails is built on, and demonstrates basic Rails concepts like ActiveRecord and scaffolding to quickly generate the necessary files for a sample student data management application.

Uploaded by

raw.junk
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 55

Slides adapted from CS 198 slides

with the gracious permission of


Armando Fox and Will Sobel

RUBY ON RAILS
CS 186 Arsalan Tavakoli
3/18/2008

Todays Agenda / Goals

Evolution of the Web


What is Ruby on Rails?
Brief overview of Ruby
Rails

CRUD
Active Records/Controller/Views
Rendering
(Too Much to List Here)

Probably wont finish it all, but serves as a


good reference

Web 1.0

Web 1.0: user interaction == server roundtrip

Other than filling out form fields


Every user interaction causes server roundtrip
Every roundtrip causes full page redraw

Web 1.5: user interactions without contacting


server

e.g. form validation before submit


e.g. selecting something from menu A causes
contents of menu B to change
But every roundtrip still causes full page redraw

Web 2.0

Separation of server roundtrip from page


rendering

Initial load of page & draw page


User interaction causes background roundtrip to
server
Response from server captured and passed to a
programmer-defined JavaScript function
That function can redraw part of the page in place
(using same mechanisms as Web 1.5)

Result: desktop-like responsive UIs that can


contact server

Auto completion
Lazy fetch of complicated parts of page
etc

What is Ruby on Rails?

Ruby is a language that is...

Rails is a web application framework that...

dynamically typed, interpreted, object-oriented,


functionally-inspired
embodies the MVC design pattern
emphasizes convention over configuration
leverages Ruby language features incl. dynamic
typing, metaprogramming, & object-orientation to
provide elegant support for both goals

Rails handles everything up to the point


where your code is called
And everything past the point where your
code delivers stuff to the user.

A Couple of Notes

We are using Rails 1.2.3, not Rails 2.0

Install RoR on your computer for easier


access

Slight differences between the two, be careful


when looking at tutorials on the web.

InstantRails for Windows


Locomotive for Mac OSx

LOTS of simple ROR tutorials out there

Rolling with Ruby on Rails (Revisited) is the


most popular and a good place to start

Ruby

Purely Object-Oriented Language

EVERYTHING is an object, and EVERYTHING


has a type

Borrows from:

Lisp, Perl, Smalltalk, and CLU

Exists outside of Rails (but the reverse isnt


true)

irb: Rubys built-in interpreter to test out


commands and test code
ri: Rubys equivalent to man

Variables

A Variable in Ruby holds objects

Since everything is an object, a variable


can hold anything!

Variable names indicate scope, not type

Local Variable: foo, bar, _temp


Instance Variable: @foo, @bar, @_temp
Symbol: :foo, :bar, :_temp
Array: [1, 1, :one]
Hash: { :one => 1, two => 2}

Review: Naming Conventions &


Syntax

ClassNames
classNewRubyProgrammer...end

method_names and variable_names


deflearn_conventions...end

predicate_like_methods?
defis_faculty_member?...end

Return values

Each method returns a single object


If no explicit return statement, then return object is
that which was last referenced.

Defreturn_10(v)
10;
End;

Review: Syntax

Syntax features

Whitespace is not significant (unlike Python)


Statements separated by semicolons or newlines
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: use a good text editor

The MVC Design Pattern

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

User actions
Directives for
rendering data

.rbController
(Ruby) code

.rhtml template
View
(or .rjs, .rxml...)
Data provided to
views

Read data
Update data

SQL table +
Model
Ruby class

A Less Trivial Example...


Lets walk through a full (single-table) MVC
example...
1.
Design the model
2.
Instantiate the model (table & Ruby
code)
3.
Basic controller to do CRUD (Create,
Read, Update, Destroy) operations on
model

SQL 001

A SQL table has a number of rows of


identical structure
Each row has several columns (fields,
attributes, etc.)
You can define relationships between
tables (associations)well get to that
later
A collection of tables & relationships is
called a schema

MVC in RoR: Convention over


Configuration
If data model is called Student:
model (Ruby class) is app/models/student.rb
SQL table is students

table row = object instance


columns = object methods (a/k/a object instance
variables)

controller methods live in


app/controllers/student_controller.rb
views are app/views/student/*.erb.html

and other types of views we'll meet later

Preview: 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

Rails ActiveRecord models


ActiveRecord, a major component of Rails...

Uses SQL tables as underlying storage, and SQL


commands as underlying manipulation, of collections of
Ruby objects
(Later) Provides an object-relationship graph abstraction
using SQL Joins as the underlying machinery

Oversimplification: 1 instance of Ruby class Foo


== 1 row in a SQL table called Foos
Let Rails do the work of creating our model and
related stuff:
script/generate scaffold student
last_name:string first_name:string
ucb_id:integer degree_expected:datetime

More to notice about


scaffolding

identical app/models/student.rb
create test/unit/student_test.rb
create test/fixtures/students.yml
For creating
create app/views/students/_form.rhtml test cases
create app/views/students/list.rhtml
onCRUD
student
create app/views/students/show.rhtml
model
views&
create app/views/students/new.rhtml
controller
create app/views/students/edit.rhtml
create app/controllers/students_controller.rb
create
test/functional/students_controller_test.rb
create app/helpers/students_helper.rb
Capture common
create app/views/layouts/students.rhtml elements of
create public/stylesheets/scaffold.css
student-related
views

Creating the Students table

Were not done yet! Students table doesnt


exist...so lets define a student

edit the migration file 001_create_students.rb


give each student a first & last name, UCB ID,
degree date

Let Rails do the work of interacting with


the database:
rake db:migrate

Question: what database?

config/database.yml

While were on SQL...


whats 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 (


id INT NOT NULL AUTO_INCREMENT,
last_name VARCHAR(255),
first_name VARCHAR(255),
ucb_sid INT(11) DEFAULT 9999
);

def self.up
create_table :students do |tbl|
tbl.column :last_name, :string
tbl.column :first_name, :string
tbl.column :ucb_sid, :integer,
:null=>false, :default=>9999
end
end
def self.down
drop_table :students
end
end

Recap

CRUD, the four basic operations on


database rows
ActiveRecord, a library that arranges to
map your models into database rows
scaffolding gets your app off the ground
early, then you can selectively replace it

captures common model of a Web front-end to


CRUD operations

convention over configuration makes


both of the above tractable to implement
while saving you work

Active Record: what is it?

A class library that provides an objectrelational 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

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

does right thing in SQL (INSERT or UPDATE)


Convention over configuration:
save

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 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 cant be saved)
:include - Prefetches joined tables
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!

Action View

A template for rendering views of the model that


allows some code embedding

Helper methods for interacting with models

commonly RHTML (.html.erb); also RXML, HAML, RJS


note...too much code breaks MVC separation
convention: views for model foo are in app/views/foo/
model valuesHTML elements (e.g. menus)
HTML form inputassignment to model objects

DRY (Dont 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

Views: Insert Ruby code snippets among HTML

Anatomy: <% code %> <%= output %>

But these form tags are generic...what about


model-specific form tags?
In the RHTML template:

<%= form_for(@student) do |f| %>


...etc....

In HTML delivered to browser:

<input id="student_last_name"
name="student[last_name]" size="30" type="text"
value="Fox" />

What happened?

Action Controller

Each incoming request instantiates a new


Controller object with its own instance
variables

Routing 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 models class methods;
idiomatically, often begins with Model.find(...)

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 modelspecific 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

example: update method

fallthrough action will call render instead


works using HTTP 302 Found mechanism, i.e.
separate browser roundtrip
fail: render the edit action again
success: redirect to URL indicated by this
@student object

alternate (older) syntax for redirects:


redirect_to :action => 'show', :id => @student.id

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, its not really a hash, but it quacks like one


Managed at dispatch level using cookies
You can keep full-blown objects there, or just ids
(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: Im 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

Controller predicates:
verify

A declarative way to assert various preconditions


on calling controller methods
You can check selectively (:only, :except) for:

And if the check fails, you can...

HTTP request type (GET, POST, Ajax XHR)


Presence of a key in the flash or the session
Presence of a key in params[]
redirect_to somewhere else
add_to_flash a helpful message

Example:
verify :method => :post, :only =>
'dangerous_action', :redirect_to => {:action =>
'index'},
:add_to_flash => "Dangerous action requires Post"

More General Filters

Code blocks that can go before, after or around controller


actions; return Boolean
before_filter :filter_method_name
before_filter { |controller| ... }
before_filter ClassName

If any before-filter returns false, chain halted & controller


action method wont be invoked

options include :only,:except, etc.


multiple filters allowed; calls provided to prepend or append to
filter chain
subclasses inherit filters but can use skip_filter methods to
selectively disable them
so filter should redirect_to, render, or otherwise deal with the
request

Simple useful example: a before-filter for nested routes!


before_filter :load_professor
def load_professor
@professor = Professor.find(params[:professor_id])
end

Intro. to Associations

Lets define a new model to represent Courses.

Whats missing: a way to identify who is in the


class!
Rails solution: (similar to database foreign keys)

keep it simple: name, CCN, start date (month & year)

Add column course_id to Students table


Declare that a Course has_many :students
Both of these are Rails conventions

Set a given students course_id field for the


course they are taking

An obvious problem with this approach...but well fix it


later

Associations In General

x has_many y

the y table has an x_id column


y belongs_to x
Note! Table structure unaffected by
whether you also define the
belongs_to....so why do it?

x has_one y

actually like has_many: does same SQL


query but returns only the first result row

Using Associations
Going forward (course has_many
students):
@c = Course.find(...)
@s = @c.students

What is the type of @s?

Going the other way (student belongs_to


course):
@s = Student.find(...)
@c = @s.course

Modeling professors

How should we change the schema to


support course belongs_to professor?

What about all the students


that a professor teaches?
@p = Professor.find(...)
@c = Professor.courses
@s = @c.students

Or....

Now we can just write:


@s = Professor.find(...).students

What is happening in terms of


tables in this example?

SQL is doing a join


Which youll learn about next time....
The message is:
Active Record tries to provide the
abstraction of an object graph by using
SQL table joins.
The xxx_id fields are called foreign keys.

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?

Wheres the accessor for


password?

Summary

ActiveRecord provides (somewhat-)databaseindependent 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

$APP_ROOT/config/routes.rb
Ruby code (that makes use of high-level
methods!) to declare rules for mapping
incoming URLs to controllers/actions
actually each rule has 2 purposes:

1.
2.

map incoming URL to ctrler/action/params


generate URL to match ctrler/action/params

e.g. when using link_to, redirect_to, etc.

Whats in a rule?

A URL template
Keywords stating what to do

Simple example

In routes.rb:

map.connect 'professors/:dept',
:controller => 'professors', :action => 'list'

In one of your views:

<%= link_to "List professors in EECS",


:controller => 'professors', :action => 'list',
:dept => 'eecs', :hired_since => 2005 %>

matching is determined by keywords


link_to uses underlying function url_for, which
consults routing rules to build the URL:

http://www.yourapp.com/professors/eecs?
hired_since=2005

Simple example cont.

In routes.rb:

map.connect 'professors/:dept',
:controller => 'professors', :action => 'list'

Now if someone visits this URL:

http://www.yourapp.com/professors/eecs

Matching is determined by position

How about:

http://www.yourapp.com/professors/eecs?
glub=1&hired_since=2006

How about:

http://www.yourapp.com/professors

Default routes

URL is compared to routing rules, one at a


time, until match found

then wildcard pieces of URL get put into

params[]

If no match, default route (last one in


routes.rb) is used

typically something like:

map.connect ':controller/:action/:id'

e.g., catches things like professors/edit/35


Warning! Can lead to dangerous behaviors

Use the root route to map the empty URL


(e.g. http://www.myapp.com):
map.root :controller=>'main', :action=>'index'

More on Routes

Ordering of routes matters; more specific


ones should come earlier so theyll match
first
map.connect 'users/:action/:id'
map.connect ':controller/:action/:id'

Many, many apps will never need to use


more than the conventional predefined
routes
If you want to, you should definitely read
more about routes offline

REST is CRUD

REST Idea: each HTTP interaction should


specify, on its own, a CRUD operation and
which object to do it on.

Rails 2.0: routes, scaffolds and URL


helpers are now all RESTful by default

GET used for read operations; POST for


writes (create, update, delete)
Also guards against spidering/bots!

result: syntax of link_to, etc. has changed

Get them by saying map.resources :model

REST and URIs


Action & named route method HTTP
to pass to url_for
method

Old style URL

show: student_url(@s)

GET

/:ctrl/show/:id

index (list): students_url

GET

/:ctrl

new: new_student_url

GET

/:ctrl/list (or
/:ctrl/index)
/:ctrl/new

create: students_url

POST

/:ctrl

destroy: student_url(@s) DELETE

/:ctrl/create
(why no ID?)
/:ctrl/destroy/:id

edit:

/:ctrl/edit/:id

/:ctrl (but see


Hack!)
/:ctrl/:id/edit

/:ctrl/update/:id

/:ctrl/:id

GET

New (RESTful)
style URL
/:ctrl/:id

/:ctrl/new

edit_student_url(@s)

update: student_url(@s) PUT

You might also like