Welcome to Giant Robots Smashing Into Other Giant Robots — a weblog about development, business, design and technology — written by thoughtbot.

simplier restful

One of the biggest features in the latest version of Rails is RESTful routes.

By writing the following in your routes.rb file (assuming you have a UsersController):

1
2
3
4
5
ActionController::Routing::Routes.draw do |map|

  map.resources :users

end

You get the following named routes for free (excluding named routes that include a :format extension):


  GET    /users         #index
  POST   /users         #create
  GET    /users/new     #new
  GET    /users/1       #show
  PUT    /users/1       #update
  GET    /users/1;edit  #edit
  DELETE /users/1       #destroy

The first column is the HTTP verb. Now Rails knows that browsers don’t support the HTTP verbs PUT and DELETE, so it fakes it by doing POSTs instead, and passing along a hidden field parameter named ‘_method’ whose value is either ‘put’ or ‘delete’.

So in order to support the basic CRUD actions in a controller, you need 4 unique routes. To me, the routes for #new and #edit are ugly. If we just had more HTTP verbs, we could eliminate both of those routes and reduce the total number of unique routes to 2 (actually, we could go all the way to just 1 route). Since Rails just uses POSTs and hidden parameters for PUT and DELETE, we can easily add our own HTTP verbs.

However, we can’t use #resources anymore in our routes.rb file though, instead we’ll have to create named routes for each of our 7 actions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
ActionController::Routing::Routes.draw do |map|

  # Create
  map.new_user 'users',
  :conditions => { :method => :new },
  :controller => 'users',
  :action => 'new'

  map.users 'users',
  :conditions => { :method => :post },
  :controller => 'users',
  :action => 'create'

  # Read
  map.users 'users',
  :conditions => { :method => :get },
  :controller => 'users'

  map.user 'users/:id',
  :conditions => { :method => :get },
  :controller => 'users',
  :action => 'show'

  # Update
  map.edit_user 'users/:id',
  :conditions => { :method => :edit },
  :controller => 'users',
  :action => 'edit'

  map.user 'users/:id',
  :conditions => { :method => :put },
  :controller => 'users',
  :action => 'update'

  # Delete
  map.user 'users/:id',
  :conditions => { :method => :delete },
  :controller => 'users',
  :action => 'destroy'

end
The above code added 2 new HTTP verbs via the new :conditions parameter:
  1. new
  2. edit
Those will handle the form display for creating a new user and editing an existing user. Now our app only needs 2 unique routes:
  1. users
  2. users/:id

We can use the normal #link_to to create links to our #new and #edit actions by using the :method parameter:

1
2
3
  link_to 'new', user_url(@user), :method => :new

  link_to 'edit', user_url(@user), :method => :edit

This really is going to create a handler for this link’s onclick event that creates a form to the specified URL and POSTs to it with a hidden parameter value for ‘_method’ of either ‘new’ or ‘edit’ (i.e. this won’t degrade gracefully with javascript disabled, if you want that you’ll need to create forms that contain nothing but a button – unfortunately #button_to doesn’t support the :method parameter).

Of course, the major downside of all this is that users can’t bookmark links to the #new and #edit pages. But I like the simplicity of only having 2 routes. You could take this all the way down to 1 route, but I think 2 is better:
  • one for the collection of users
  • one for an individual user

About this entry

 

thoughtbot is hiring

We are hiring web developers and web designers in both Boston and New York, NY.

What are we up to?

We built Shoulda, an eclectic set of additions to Test::Unit; Paperclip to manage uploaded files without hassle; Jester, a REST/ActiveResource client library written in Javascript, and Squirrel, an enhancement for ActiveRecord's find syntax; — amongst some other projects.


Chad (President) and Jon (CTO) co-authored a technical book titled Pro Active Record: Databases with Ruby and Rails, which explores the ins and outs of the ActiveRecord ruby library. You can buy it today at Amazon.com.

About thoughtbot, inc.

We are a small web application development consulting business, with offices in Boston, MA and New York, NY. If you're looking to find a team for your next web development project or your new web application — get in touch.