This one cost me at least an hour of frustration.
So apparently the Rails router has considered the dot (“.”) to be a “separator” character along with the slash (“/”) since version 1.2. I don’t know in what context this ever seemed like a good idea, but whatever. It’s not the sort of thing that’s going to bite you every day, but when it does it will be in very weird ways. To wit:
First, a simple routes.rb.
resources :users do resources :projects end
Fill in some typical values, and you get a path:
irb(main):009:0> app.user_projects_path("avdi") => "/users/avdi/projects"
Now fill in a value with a period in it, and watch it explode:
irb(main):010:0> app.user_projects_path("avdi.grimm") ActionController::RoutingError: No route matches { :user_id=>"avdi.grimm", :action=>"create", :controller=>"projects" }
:action => "create"
? What?!! Who said anything about create?!
As it turns out, there is an invocation in your routes file which will fix this:
resources :users, :constraints => { :id => /.*/ } do resources :projects end
irb(main):013:0> app.user_projects_path("avdi.grimm") => "/users/avdi.grimm/projects"
Now I know what you’re thinking. “That’s so obvious, why didn’t he think of that immediately?” What can I say, some days I’m slow.
UPDATE: Here’s the Rails 2.* version:
resources :users, :requirements => { :id => /.*/ } do resources :projects end
And here’s a version that accepts anything BUT slashes for the parameter value:
resources :users, :requirements => { :id => /[^/]+/ } do resources :projects end
I guess the “.” became all about response_for and response formats. I find Rails routing awkward often, though like the arch of your conundrum above, I can usually get the routing the way I want it after a brief visit or two to Hades on the way.
I guess the “.” became all about response_for and response formats. I find Rails routing awkward often, though like the arch of your conundrum above, I can usually get the routing the way I want it after a brief visit or two to Hades on the way.
THANK YOU! I'm glad I found this post quickly, I was prepared to beat my head against this for quite a while.
Thank you so much! Exactly what I needed.
thanks! for many resourses we can do something like:
[:users, ::posts, ::comments].each { |r| resources r, :constraints => { :id => /.*/ } }
By allowing /.*/ you bust your regular respond_to blocks though, don’t you? I mean if “foo” is a valid userid and the url is “foo.xml”, it’s going to try to find a “foo.xml” user instead of rendering xml for the foo user.
Is there a catch-all respond_to we can use instead?
Thanks for sharing this. I learned not one, but two things from your post!.
Not particularly germane to the subject at hand, but in Rails 3.1.x (3.0.x?) you can tighten up your route constraint:
resources :users, :constraints => { :id => /.*/ } do
like so:
resources :users, :id => /.*/ do
AWESOME! And completely germaine. Thanks!
Thanks Avdi – just ran into this
Thank you bro I was using some unique string to replace with dot :).