1 / 24

Routes & REST & URL-helpers & validations & filters

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

sonja
Download Presentation

Routes & REST & URL-helpers & validations & filters

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


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

  2. 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

  3. 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

  4. $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: • map incoming URL to ctrler/action/params • 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

  5. 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

  6. 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

  7. 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'

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

  9. 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 sayingmap.resources :model

  10. REST and URI’s

  11. 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

  12. 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

  13. That whole thing withrespond_to do |format| • Let’s make it easier to read by: • put the if...elseoutside the do block • change variable name format to wants

  14. 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)

  15. 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.

  16. 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

  17. Enter nested RESTful routes map.resources :professors do |p| p.resources :courses end —or— map.resources :professors, :has_many=>:courses • Now you can say course_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!

  18. 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... end def update ...if update of Course fails... redirect_to([@professor,@course]) end

  19. 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) %>

  20. 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

  21. 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)

  22. 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"

  23. 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 • 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_professor def load_professor @professor = Professor.find(params[:professor_id]) end

  24. 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!

More Related