Christian Johansen
Christian Johansen

Reputation: 2031

Rails 3 Routing: Resource actions and nested resource with :path => "/"

I want to configure my Rails routing such that these cases work:

/username           #=> { :controller => "houses",
                    #     :action => "index",
                    #     :user_id => "username" }

/username/housename #=> { :controller => "houses",
                    #     :action => "show",
                    #     :user_id => "username",
                    #     :id => "housename" }

/username/edit      #=> { :controller => "users",
                    #     :action => "edit",
                    #     :id => "username" }

In other words, I want /:user_id to be a regular user resource, and have a nested resource for it, which is mounted directly on the root. So, I want /username/housename instead of /username/houses/housename. I tried using :path => "/" for the nested resources, but this somehow clashes with other actions such as `:edit. I'm lost - can this be done?

Upvotes: 3

Views: 438

Answers (2)

Chris Salzberg
Chris Salzberg

Reputation: 27374

What you are trying to do will create conflicts, which is why Rails is not letting you do it.

Consider the situation where some user bob has a house named "edit". In this case, where is Rails supposed to route '/bob/edit' to? There are two possibilities:

{ :controller => "houses", :action => "show", :user_id => "bob", :id => "edit" }

and:

{ :controller => "users", :action => "edit", :id => "bob" }

So to answer your question, as is what you are trying to do cannot be done until you remove the ambiguity.

UPDATE:

Borrowing from @sevenseacat's answer, I think this should do what you want, in the case of a route /bob/edit prioritizing the edit action for user "bob" over the show action for a house named "edit":

resources :users, path: '/', only: :edit
resources :users, path: '/', only: :show do
  resources :houses, only: :show, path: ''
end

I get these routes:

  edit_user GET /:id/edit(.:format)     users#edit
 user_house GET /:user_id/:id(.:format) houses#show
       user GET /:id(.:format)          users#show

Notice that the edit_user path appears above the user_house path, which guarantees that it will get priority when there is a conflict.

Upvotes: 2

sevenseacat
sevenseacat

Reputation: 25029

Something like this may be what you're after:

resources :users, path: '/', only: [:show, :edit] do
  resources :houses, only: [:show], path: ''
end

rake routes tells me:

user_house GET    /:user_id/:id(.:format)     houses#show
 edit_user GET    /:id/edit(.:format)         users#edit
           GET    /:id(.:format)              users#show

Upvotes: 1

Related Questions