Have you ever wondered how Rails’ RESTful Routes create URL mappings that can only be accessed by certain HTTP methods?
For example, map.resources :users creates an entire set of named routes that can only be accessed with the appropriate HTTP method. GET’ing users_path maps to a different controller method than POST’ing to users_path (see the documentation and the free PeepCode cheatsheet for more details).
The answer is the undocumented :conditions parameter for ActionController::Routing::RouteSet#add_route. It’s kind of sad when the best documentation available for one of Rails’ most powerful features is from a Python re-implementation.
But once you know it’s there, it’s really easy to use :conditions to create your own HTTP-savvy routes, simplifying your URLs in the process.
Let’s say you’ve got a form that sends e-mail. You need two actions: one to show the form, and one to send the mail.
1 2 3 4 |
ActionController::Routing::Routes.draw do |map| map.show_form '/contact', :controller => 'contact', :action => 'show_form' map.send_mail '/send', :controller => 'contact', :action => 'send_mail' end |
But with :conditions, you can consolidate these two URLs into a single URL that responds differently to GET and POST requests.
1 2 3 4 |
ActionController::Routing::Routes.draw do |map| map.show_form '/contact', :controller => 'contact', :action => 'show_form', :conditions => {:method => :get} map.send_mail '/contact', :controller => 'contact', :action => 'send_mail', :conditions => {:method => :post} end |
This keeps your URLs simple, and ensures that your methods are hit with the proper HTTP verb.
P.S.: Interested in how RESTful routes work? Check out the code and take a look at the routes it generates, as produced by the Route Navigator plugin.
