Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 3 level deep nested resources

I know many rails developers say that nesting your resources more then 2 levels deep is wrongdoing. I also agree because it gets messy when your urls looks like mysite.com/account/1/people/1/notes/1. I am trying to find a way to use nested resources but without nesting them 3 levels deep.

This is the wrong way of doing it since rails developers do not recommend it and also it's very difficult figuring out how to nest this in the controller or form view.

resources :account do 
  resources :people do
    resources :notes
  end
end

The correct way rails developer say this should be done is like so

resources :account do 
  resources :people
end

resources :people do
  resources :notes
end

Here's the problem that I always run into. When ever I visit account/1/people I can add a person to the account and lets say the url is like so mysite.com/account/1/people/1 and that works fine.

Now if I try to access the mysite.com/people/1/notes from account 1 I get the error

Can't find people without and account id

How can get this to work properly?

like image 437
Yooku Avatar asked May 19 '12 00:05

Yooku


1 Answers

You nest the routes as deep as you like as rails 3.x allows you to flatten them using shallow: true

Try experimenting with

resources :account, shallow: true do 
  resources :people do
    resources :notes
  end
end

Use rake routes to see what you get :)

UPDATE in response to comment

As I said, play with rake routes to see what url's you can get

resources :account, shallow: true do 
  resources :people, shallow: true do
    resources :notes
  end
end

gets you these routes

:~/Development/rails/routing_test$ rake routes
      person_notes GET    /people/:person_id/notes(.:format)        notes#index
                   POST   /people/:person_id/notes(.:format)        notes#create
   new_person_note GET    /people/:person_id/notes/new(.:format)    notes#new
         edit_note GET    /notes/:id/edit(.:format)                 notes#edit
              note GET    /notes/:id(.:format)                      notes#show
                   PUT    /notes/:id(.:format)                      notes#update
                   DELETE /notes/:id(.:format)                      notes#destroy
    account_people GET    /account/:account_id/people(.:format)     people#index
                   POST   /account/:account_id/people(.:format)     people#create
new_account_person GET    /account/:account_id/people/new(.:format) people#new
       edit_person GET    /people/:id/edit(.:format)                people#edit
            person GET    /people/:id(.:format)                     people#show
                   PUT    /people/:id(.:format)                     people#update
                   DELETE /people/:id(.:format)                     people#destroy
     account_index GET    /account(.:format)                        account#index
                   POST   /account(.:format)                        account#create
       new_account GET    /account/new(.:format)                    account#new
      edit_account GET    /account/:id/edit(.:format)               account#edit
           account GET    /account/:id(.:format)                    account#show
                   PUT    /account/:id(.:format)                    account#update
                   DELETE /account/:id(.:format)                    account#destroy

As can be seen, you have access to all models at whatever level you decide you need. The rest is down to whatever you put in your controller actions.

You really have to work on the actions to make sure you take appropriate action when id params are not passed in, so if you make use of an id for a specific model then check that the id is in the params list and if not take alternative action. e.g. if you don't pass the account id in then make sure you don't try to use it

your comment states that you already use shallow routes, but that's not what you posted in your question?

like image 97
jamesc Avatar answered Oct 19 '22 20:10

jamesc