UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0...

24
UC Berkeley Routes & REST & URL- helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox

Transcript of UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0...

Page 1: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

UC Berkeley

Routes & REST & URL-helpers & validations &

filtersCS 98-10/CS 198-10

Web 2.0 Programming Using Ruby on RailsArmando Fox

Page 2: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

Administrivia

• Office hours switched (again...sorry)– Tuesdays 1:30-2:30 in 413 Soda

• Monday: Project brainstorming• Weds: Project groups informally chosen-up

• By following Monday: start planning your app (user stories, testing, deployment....)

• Technical material: Routes & REST (today), more on controllers & views

Page 3: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

Outline...

• Routing basics: how do....– URLs get mapped to a controller and action?– link_to, redirect_to etc. generate their URLs?

• REST and RESTful routes– what is RESTful resource access?– how Rails 2.0 routing supports REST

• URL helpers– generating URL’s (for your pages) that will map to specific controller actions...RESTfully

• Further reading– “Rails Way” book has good content on this– “Agile” book has routes, but not 2.0 routes and REST

• Model validations, callbacks, controller filters

Page 4: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

$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. map incoming URL to ctrler/action/params2. generate URL to match

ctrler/action/params– e.g. when using link_to, redirect_to, etc.

– What’s in a rule?– A URL template– Keywords stating what to do

Page 5: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

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

Page 6: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

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

Page 7: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

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'

Page 8: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

More on Routes

• Ordering of routes matters; more specific ones should come earlier so they’ll match firstmap.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

Page 9: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

REST is CRUD

• REST Idea: each HTTP interaction should specify, on its own, a CRUD operation and which object to do it on.– GET used for read operations; POST for writes (create, update, delete)

– Also guards against spidering/bots!

• Rails 2.0: routes, scaffolds and URL helpers are now all RESTful by default– result: syntax of link_to, etc. has changed

• Get them by saying map.resources :model

Page 10: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

REST and URI’s

Action & named route method to pass to url_for

HTTP method

Old style URL

New (RESTful) style URL

show: student_url(@s) GET /:ctrl/show/:id

/:ctrl/:id

index (list): students_url

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

/:ctrl

new: new_student_url GET /:ctrl/new /:ctrl/new

create: students_url POST /:ctrl/create (why no ID?)

/:ctrl

destroy: student_url(@s)

DELETE /:ctrl/destroy/:id

/:ctrl (but see Hack!)

edit: edit_student_url(@s)

GET /:ctrl/edit/:id

/:ctrl/:id/edit

update: student_url(@s)

PUT /:ctrl/update/:id

/:ctrl/:id

Page 11: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

The DELETE & PUT hack

• REST says: use HTTP method DELETE to request deletion; PUT to request Update – But: Web browsers only have GET and POST

• “Solution”: use POST, but include extra field _method with value DELETE or PUT– routing takes care of parsing this out to disambiguate dispatching

– done with JavaScript in link_to (but you shouldn’t be using link_to for this...why?)

– or use button_to which creates a self-contained form for a single button

Page 12: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

How url_for has changed

Excerpted from REST Cheat Sheet which I’m trying to get a site license for (Peepcode)Note use of either _path or _url suffix

Page 13: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

That whole thing withrespond_to do |format|

• Let’s make it easier to read by:– put the if...else outside the do block– change variable name format to wants

Page 14: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

Easier-to-read version

• respond_to accepts a block, and yields to it passing the wants object

• wants’s instance methods named for possible MIME output types (HTML, XML, etc.)

• Each of those methods takes a block that specifies what to do for each format– Based on parsing HTTP headers from request– Many, many MIME types predefined (add more in environment.rb)

– A useful one when we do AJAX: js (runs .rjs template if available)

Page 15: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

What about redirect_to?

• RESTful routing strikes again!– url_for and friends now assume RESTful routes by default

• Hint: consider url_for(@student)– Or redirect_to(edit_student_path(@student)), etc.

Page 16: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

Nested routes

• Consider a Course that belongs_to :professor (and as well, Professor has_many :courses)

• In particular, it makes no sense to have a course without a professor– in our app, I mean

• When invoking CRUD methods on a course, we’d like to be able to specify which professor it belongs_to

Page 17: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

Enter nested RESTful routes

map.resources :professors do |p| p.resources :coursesend

—or—map.resources :professors, :has_many=>:courses

• Now you can saycourse_path(:professor_id=>3, :id=>20)

and get a RESTful URI for course ID 20 that belongs to professor ID 3.

• Note! The route builder doesn’t check if the belongs_to relationship keys match what’s in the database!

Page 18: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

In Courses controller...

• Need to set up the @professor that owns the course in each of the methods– Otherwise the URL-builder methods won’t know what the parent object ID is

• Ugly (we’ll learn a better way with filters):

def index @professor = Professor.find(params[:professor_id]) @courses = @professor.courses.find(:all)...etc...enddef update ...if update of Course fails... redirect_to([@professor,@course])end

Page 19: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

What about views for nested models?

# example: views/courses/edit.html.erb

<% form_for([@professor,@course]) do |f| %> <%= f.text :description %> <%= f.text :ccn %> <%= f.submit "Save Changes" %><% end %><%= link_to "Show", [@professor,@course]) %> or... link_to "Show", course_path(@course) if makes sense <%= link_to "Back", professor_courses_path(@professor) %>

Page 20: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

In your index (list) view...

<% @courses.each do |c| %> <tr> <td> c.name </td> <td><%= link_to "Edit",edit_course_path([@professor,c]) %>

</td> <td><%= link_to "Show",course_path([@professor,c])%></td> <td> <%= button_to "Destroy", course_path([@professor,c]),:method=>:delete %></td> </tr><% end %>

• Similarly for other views

Page 21: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

Worth understanding...

• Routing and REST caused lots of changes in 2.0, but ultimately they will make life better

• Best tutorial we’ve found (thx Arthur!):

http://www.akitaonrails.com/2007/12/12/rolling-with-rails-2-0-the-first-full-tutorial

(Linked from course home page)

Page 22: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

Controller predicates: verify

• A declarative way to assert various preconditions on calling controller methods

• You can check selectively (:only, :except) for:– HTTP request type (GET, POST, Ajax XHR)– Presence of a key in the flash or the session– Presence of a key in params[]

• And if the check fails, you can...– 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"

Page 23: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

More General Filters• Code blocks that can go before, after or around

controller actions; return Booleanbefore_filter :filter_method_namebefore_filter { |controller| ... }before_filter ClassName

– 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• If any before-filter returns false, chain halted &

controller action method won’t be invoked– so filter should redirect_to, render, or otherwise deal with

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

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

Page 24: UC Berkeley Routes & REST & URL-helpers & validations & filters CS 98-10/CS 198-10 Web 2.0 Programming Using Ruby on Rails Armando Fox.

A General Pattern:“Do It Declaratively”

• More and more ways to specify what should be done rather than how to do it

• Should always be asking yourself this question

• Especially when you find yourself (re)writing common code in multiple places!