Rails Namespaces Rock. Rails Namespaces Suck.
So this evening (can we still call it evening at 4:30am?) I encountered a frustrating issue. I’m working on a rails site for a photographer friend and it’s been coming along rather smoothly. However, tonight I ran into an annoyingly frustrating issue that turns out to have been caused some routes namespace gotchas.
Let me explain:
The site I’m putting together has an admin section, a client section and (of course) a public section. It only seems logical to namespace the different sections of the site for pretty urls and easier controller management. With that in mind, I needed a few controllers to handle the three sections. So, for instance, I had PicturesController, Client::PicturesController and Admin::PicturesController. And here’s what I initially had in my routes.rb file to handle the routing:
map.namespace :client do |client|
client.resources :pictures, :member => { :approve => :put, :reject => :put }
client.resources :albums, :has_many => [:pictures]
end
map.namespace :admin do |admin|
admin.resources :pictures, :collection => {:bulk_edit => :put, :bulk_update => :post}
admin.resources :albums
admin.resources :clients, :has_many => [:pictures, :albums]
end
# and of course the default
map.connect ':controller/:action/:id'
With those namespaces in place, I aught to have been able to navigate to the following urls with no problem:
/admin/pictures/* /client/pictures/* /pictures/* /admin/albums/* /client/albums/*
And, when running things locally, I could. Not only that, when the app was running in production mode on the server, I could navigate to those URLs without problem as well…sometimes. But every once in a while (and it seemed to become more frequent the longer the mongrel process had been running), I would get a 404 error in the browser. You could usually get through to the actual page by refreshing a few times, but who wants to (or should have to) to that?! Frankly, it was pissing me off. On to the logs…
Checking the production.log was no help — ActionController::UnknownAction (No action responded to index) — really?! really?! Because I’m looking at the index action right now. Don’t try to tell me that it’s not there!
So, since production.log wasn’t playing by my rules, I decided to peruse the mongrel log. And this is what I found:
warning: toplevel constant PicturesController referenced by Admin::PicturesController
It was a warning I had never seen before. A little strange, but basically the toplevel PicturesController was stepping on the Admin::PicturesController’s toes, stomping all up and down on its methods. It’s a strange thing, but apparently there are issues with route namespaces in rails. To be honest though, I’m not sure it’s a flaw in Rails—it may be the nature of Ruby and the fact that you can’t have a class and a module of the same name. Either way, it was a frustrating thing to try and figure out. Eventually I found a bit of direction via a thread in the Ruby on Rails Google group (http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/e4a1e5f532f53785/f9a982286459d74c?lnk=raot).
All’s well that ends well, but I have to say, this one was a doozy—it’s always a pain to track down a bug that can’t be reproduced locally and also happens only intermittently. Hope this is helpful to someone.
And I’m still not tired…
UPDATE: I just realized I didn’t mention what the solution was to this problem. Basically, just rename your controllers so that they each have a unique name (this could be as simple as making one singular and the other plural). Kind of annoying, but it’s a pretty easy solution to a very frustrating problem.
Posted by Phil Burrows, Rails Developer on Friday, May 02, 2008