Reputation: 2693
I'm trying to figure out how to nest routes in Rails 5 (so that related controllers are kept together.
I have my controllers file tree set up as:
app/controllers/users
In that folder, I have controllers for:
identities_controller.rb
app_roles_controller.rb
Each of those controllers is saved as:
class Users::IdentitiesController < ApplicationController
class Users::AppRolesController < ApplicationController
My routes file has:
resources :app_roles,
:controllers => {
:app_roles => 'users/app_roles'
}
devise_for :users,
:controllers => {
:sessions => 'users/sessions',
:registrations => "users/registrations",
:omniauth_callbacks => 'users/omniauth_callbacks'
}
resources :identities,
:controllers => {
:identities => 'users/identities'
}
resources :users
In my views folder, all of the files are top-level. Im unclear as to whether I need to group them in the same way that I do my controllers.
When I save all of this and try to navigate to http://localhost:3000/app_roles#index, I expect to go to my app/views/app_roles/index.
Instead, I get an error that says:
app_roles
uninitialized constant AppRolesController
When I rake routes, I get:
rake routes | grep app_roles
app_roles GET /app_roles(.:format) app_roles#index {:controllers=>{:app_roles=>"users/app_roles"}}
POST /app_roles(.:format) app_roles#create {:controllers=>{:app_roles=>"users/app_roles"}}
new_app_role GET /app_roles/new(.:format) app_roles#new {:controllers=>{:app_roles=>"users/app_roles"}}
edit_app_role GET /app_roles/:id/edit(.:format) app_roles#edit {:controllers=>{:app_roles=>"users/app_roles"}}
app_role GET /app_roles/:id(.:format) app_roles#show {:controllers=>{:app_roles=>"users/app_roles"}}
PATCH /app_roles/:id(.:format) app_roles#update {:controllers=>{:app_roles=>"users/app_roles"}}
PUT /app_roles/:id(.:format) app_roles#update {:controllers=>{:app_roles=>"users/app_roles"}}
DELETE /app_roles/:id(.:format) app_roles#destroy {:controllers=>{:app_roles=>"users/app_roles"}}
To me, I think these routes show that app_roles#index should go to the app/views/app_roles/index.html.erb via the controller in app/controllers/users/app_roles_controller.rb
I have the same issue with the identities resource.
GUESSES I tried moving the app/views/app_roles folder to be nested under the users folder (i.e. app/views/users), but I get the same error when I then try to go to the http://localhost:3000/app_roles#index to check if it works.
I also tried amending the routes file to:
resources :app_roles,
:resources => {
:app_roles => 'users/app_roles'
}
By that, I mean that I changed the reference to :controllers, to :resources. It didn't work - I get the same error.
Can anyone see what I'm doing wrong?
Upvotes: 2
Views: 775
Reputation: 102134
To route resources to a "namespaced" controller you can use the module
option:
resources :identities, module: :users
Or scope module:
which is useful when declaring multiple resources:
scope module: :users do
resources :app_roles, module: :users
resources :identities, module: :users
end
Which is much cleaner than specifying the controller manually which is really only done when you are overriding a library like Devise or when the controller and route names don't line up.
The termology here can be somewhat confusing. Just remember that the only thing a route does is match an incoming request with a controller. It does not influence how the controller does its job.
To me, I think these routes show that app_roles#index should go to the app/views/app_roles/index.html.erb via the controller in app/controllers/users/app_roles_controller.rb
Well thats not how it works. Rails looks up views based on the nesting of the controller class. Thus rails will look for the views for Users::IdentitiesController
in views/users/indentities/
.
If you want to break with the conventions you can explicitly render the views or prepend/append the view paths. However learn the conventions before you break them, they are actually pretty smart.
Note that your routes do not influence how your controllers lookup views. Thats just up to the module nesting - which is how the object is composed. And has absolutely nothing to do with the concept of nested routes.
The routes you are generating are not nested. A nested route would be for example:
POST /users/:user_id/identities
Which clearly describes the intent. To setup a nested routes for indentities
you would do:
resources :users, shallow: true do
scope module: :users do
resources :identities
end
end
shallow: true
generates the individual routes without the users/:used_id/
prefix.
Prefix Verb URI Pattern Controller#Action
user_identities GET /users/:user_id/identities(.:format) users/identities#index
POST /users/:user_id/identities(.:format) users/identities#create
new_user_identity GET /users/:user_id/identities/new(.:format) users/identities#new
edit_identity GET /identities/:id/edit(.:format) users/identities#edit
identity GET /identities/:id(.:format) users/identities#show
PATCH /identities/:id(.:format) users/identities#update
PUT /identities/:id(.:format) users/identities#update
DELETE /identities/:id(.:format) users/identities#destroy
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
Upvotes: 1