Routing for a Singleton Resource on Rails 2

RailsWhile developing your RESTful Rails application, you use ActionController::Resources which magically generates a bunch of named routes to use in controllers and views.

For example, adding the following line to your config/routes.rb:

map.resources :products

gives you these paths: products_path, product_path(id), new_product_path and edit_product_path(id).

If your resource is a singleton one, you should simply do this:

map.resource :store

However, when you try to navigate to the edit action (/store/edit) you will get an error like this:

You have a nil object when you didn't expect it!
The error occurred while evaluating nil.to_sym

from the line that says <% form_for(@store) do |f| %> in your view.

I've discovered that there is already an open ticket for this issue. The problem is that Rails still assumes a collection resource. To fix this, you need to explicitly add the path to the form_for helper:

<% form_for(@store, :url => store_path) do |f| %>

Also, you will need to do the same in your update action:

redirect_to(store_path)

Now, if you are like me, you may try to use a singular name for your controller (StoreController). Now, you should get the next error:

uninitialized constant StoresController

Who mentioned StoresController?!

Well, Rails did! As documented here, the default controller name is still taken from the plural name.

To solve this, just add the controller name to your route:

map.resource :store, :controller => 'store'

Now, everything should work fine.

By the way, I have found a patch that allows scaffold generator to produce singleton resources: http://dev.rubyonrails.org/ticket/8832. But I didn't try it yet. Anyone did?

Did you like this article? Bookmark it:

Related Articles

5 Comments

  • Thanks a lot for this. I was about to throw myself in front of a bus.

  • You are welcome, Gustavo. I'm glad I saved your life :)

  • Very helpful ,thanks :))

  • Thanks! Been working 2 hours to try to get this to work and finally realized...it's a stupid rails bug

  • This doesn't work for 2.3.4 (and possibly earlier 2.3 versions). The list, edit, show, update are all fine, but the new fails with "customer_url failed to generate from {:controller=>"customer", :action=>"show"} - you may have ambiguous routes ...". Using map.resource customer :singular=>"customer_instance fixes the issue with new, but breaks the others! Not very restful, and not very dry:(

Leave a Comment

If you want to post code, do this:
<pre><code class="ruby|javascript|css|html"> your code here </code></pre>