A Blog

Rails 3 Routing Gotcha

December 07, 2010

Since I have a certain level of self-loathing I decided to upgrade our app to the latest version of Rails (as of now, 3.0.3). Rails 3 is a big upgrade and change from Rails 2. One of the biggest areas getting a facelift is the routing system. In general this guide does a great job explaining everything, but I recently ran into a rather specific wall. By default Rails prefers you to use what they call {:controller => 'photos', :action => 'dothat'} ) do |f| %> It generated the correct URL: photos/1/dothat, which I confirmed by calling rake routes at the command line.  After searching the Interent and only getting frustrated I finally saw something that jogged my memory. In REST, 'post' is for creating new resources. I was editing my model. Simply changing it to:     put :dothat Fixed everything.  I'll attribute that mixup to years and years of having only GET and POST available drilled into my head. It doesn't exactly help that Rails doesn't use a "real" PUT in the form's method attribute. It uses POST, but includes a hidden input, "_method" to store the verb it should respond to." title="" src="/static/fa6642210dddfe3866da1de1d2206d13/f8fb9/1291761300000.jpg" srcset="/static/fa6642210dddfe3866da1de1d2206d13/e8976/1291761300000.jpg 148w, /static/fa6642210dddfe3866da1de1d2206d13/63df2/1291761300000.jpg 295w, /static/fa6642210dddfe3866da1de1d2206d13/f8fb9/1291761300000.jpg 590w, /static/fa6642210dddfe3866da1de1d2206d13/d7649/1291761300000.jpg 632w" sizes="(max-width: 590px) 100vw, 590px" />

Since I have a certain level of self-loathing I decided to upgrade our app to the latest version of Rails (as of now, 3.0.3). Rails 3 is a big upgrade and change from Rails 2. One of the biggest areas getting a facelift is the routing system.

In general this guide does a great job explaining everything, but I recently ran into a rather specific wall. By default Rails prefers you to use what they call ”RESTful Routes”. I’m rather indifferent to the idea, but I go along with it. This provides you with 7 default routes for a resource. For example, say you create routes for a Model called “Photo”. This will create the following routes (stolen from the aforementioned guide):

This kind of approach works for 95% of my needs, but sometimes you just need to define something beyond the defaults. Say you need an action called “DoThis”. You can simply modify your Photo route like so:

resources :photos do
  member do
    get :dothis
  end
end

And then /photos/1/dothis will map to a dothis method in your controller. This works as expected, but I needed to submit a form to a custom route as well. So, I just added this to my member do function:

post :dothat

I then attempted to submit a form to the dothat action, but got a Routing Error telling me the route wasn’t found. I double checked and the URL was definitely correct.

<%= form_for(@photo, :url => {:controller => 'photos', :action => 'dothat'} ) do |f| %>

It generated the correct URL: photos/1/dothat, which I confirmed by calling rake routes at the command line.

After searching the Interent and only getting frustrated I finally saw something that jogged my memory.

In REST, ‘post’ is for creating new resources. I was editing my model. Simply changing it to:

put :dothat

Fixed everything.

I’ll attribute that mixup to years and years of having only GET and POST available drilled into my head. It doesn’t exactly help that Rails doesn’t use a “real” PUT in the form’s method attribute. It uses POST, but includes a hidden input, ”_method” to store the verb it should respond to.


Scott Williams

Written by Scott Williams who lives and works in sunny Phoenix, AZ. Twitter is also a place.