So I am trying to nest resources under a namespace, however when i try to navigate to the UserProfile new page I am hitting the following error:
ActionController::RoutingError at /users/xxxxxx/user_profiles/new
uninitialized constant AccountManagementPages::UserProfilesController
Did you mean? AccountManagementPages::UsersController
This is how the resources are set up in my routes.rb file
constraints(AccountManagement) do
namespace :account_management_pages, path: '' do
root to: 'users#new', as: :registration
resources :users, except: %w[index], path_names: { new: 'register' } do
resources :user_profiles
end
end
end
my file structure for both my controller and views are configured correctly (at least I thought they were).
And here is how my views are nested.
This is how I have my user_profiles_controller configured:
module AccountManagementPages
module Users
class UserProfilesController < ApplicationController
def show; end
def new; end
def edit; end
def create; end
def update; end
end
end
end
and my model associations (don't think this is overly relevant here but just incase it is.)
class User < ApplicationRecord
has_one :user_profile, dependent: :destroy
end
class UserProfile < ApplicationRecord
belongs_to :user
end
any help here would be greatly appreciated. Not sure why I am hitting this error?
Thanks in advance.
If you do rails routes, you'll get (amongst other things):
Prefix Verb URI Pattern Controller#Action
account_management_pages_registration GET / account_management_pages/users#new
account_management_pages_user_user_profiles GET /users/:user_id/user_profiles(.:format) account_management_pages/user_profiles#index
POST /users/:user_id/user_profiles(.:format) account_management_pages/user_profiles#create
new_account_management_pages_user_user_profile GET /users/:user_id/user_profiles/register(.:format) account_management_pages/user_profiles#new
edit_account_management_pages_user_user_profile GET /users/:user_id/user_profiles/:id/edit(.:format) account_management_pages/user_profiles#edit
account_management_pages_user_user_profile GET /users/:user_id/user_profiles/:id(.:format) account_management_pages/user_profiles#show
PATCH /users/:user_id/user_profiles/:id(.:format) account_management_pages/user_profiles#update
PUT /users/:user_id/user_profiles/:id(.:format) account_management_pages/user_profiles#update
DELETE /users/:user_id/user_profiles/:id(.:format) account_management_pages/user_profiles#destroy
account_management_pages_users POST /users(.:format) account_management_pages/users#create
new_account_management_pages_user GET /users/register(.:format) account_management_pages/users#new
edit_account_management_pages_user GET /users/:id/edit(.:format) account_management_pages/users#edit
account_management_pages_user GET /users/:id(.:format) account_management_pages/users#show
PATCH /users/:id(.:format) account_management_pages/users#update
PUT /users/:id(.:format) account_management_pages/users#update
DELETE /users/:id(.:format) account_management_pages/users#destroy
As you can see, user_profiles is not nested under the users namespace. Rails, therefore, is expecting:
module AccountManagementPages
class UserProfilesController < ApplicationController
...
end
end
If you do:
constraints(AccountManagement) do
namespace :account_management_pages, path: '' do
root to: 'users#new', as: :registration
resources :users, except: %w[index], path_names: { new: 'register' } do
scope module: :users do
resources :user_profiles
end
end
end
end
...and then rails routes, you get (amongst other things):
Prefix Verb URI Pattern Controller#Action
account_management_pages_registration GET / account_management_pages/users#new
account_management_pages_user_user_profiles GET /users/:user_id/user_profiles(.:format) account_management_pages/users/user_profiles#index
POST /users/:user_id/user_profiles(.:format) account_management_pages/users/user_profiles#create
new_account_management_pages_user_user_profile GET /users/:user_id/user_profiles/register(.:format) account_management_pages/users/user_profiles#new
edit_account_management_pages_user_user_profile GET /users/:user_id/user_profiles/:id/edit(.:format) account_management_pages/users/user_profiles#edit
account_management_pages_user_user_profile GET /users/:user_id/user_profiles/:id(.:format) account_management_pages/users/user_profiles#show
PATCH /users/:user_id/user_profiles/:id(.:format) account_management_pages/users/user_profiles#update
PUT /users/:user_id/user_profiles/:id(.:format) account_management_pages/users/user_profiles#update
DELETE /users/:user_id/user_profiles/:id(.:format) account_management_pages/users/user_profiles#destroy
account_management_pages_users POST /users(.:format) account_management_pages/users#create
new_account_management_pages_user GET /users/register(.:format) account_management_pages/users#new
edit_account_management_pages_user GET /users/:id/edit(.:format) account_management_pages/users#edit
account_management_pages_user GET /users/:id(.:format) account_management_pages/users#show
PATCH /users/:id(.:format) account_management_pages/users#update
PUT /users/:id(.:format) account_management_pages/users#update
DELETE /users/:id(.:format) account_management_pages/users#destroy
...and user_profiles will be nested under users. And you should be able to use:
module AccountManagementPages
module Users
class UserProfilesController < ApplicationController
...
end
end
end
Related
Rails routes create the 7 CRUD actions by default following REST.
resources :users
However, I have a confirm_destroy action that I use in almost every resource, because I have a lot of logic that goes on the confirmation page; it's not just a simple yes/no alert dialog.
resources :users do
get :confirm_destroy, on: :member
end
With 50+ resources, it gets tedious to write this out for each resource and my routes file is literally 3x longer because of this.
Is there any way to add an action to the standard 7 for the resources block such that
resources :users
would be the same as
resources :users do
get :confirm_destroy, on: :member
end
and I can use it in the routes as a standard action, ie:
resources :users, only: [:show, :confirm_destroy, :destroy]
resources :users, except: [:confirm_destroy]
While not quite as elegant as you might like, the Rails way would be to use a routing concern, as #dbugger suggested.
For example:
concern :confirmable do
get 'confirm_destroy', on: :member
end
resources :users, :widgets, concerns: :confirmable
$ rails routes
Prefix Verb URI Pattern Controller#Action
confirm_destroy_user GET /users/:id/confirm_destroy(.:format) users#confirm_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
confirm_destroy_widget GET /widgets/:id/confirm_destroy(.:format) widgets#confirm_destroy
widgets GET /widgets(.:format) widgets#index
POST /widgets(.:format) widgets#create
new_widget GET /widgets/new(.:format) widgets#new
edit_widget GET /widgets/:id/edit(.:format) widgets#edit
widget GET /widgets/:id(.:format) widgets#show
PATCH /widgets/:id(.:format) widgets#update
PUT /widgets/:id(.:format) widgets#update
DELETE /widgets/:id(.:format) widgets#destroy
I have a controller in a name spaced controller/user directory, so its first line is
class User::BookingsController < ApplicationController
I have set the routes as follows
resources :users do
namespace :user do
resources :bookings
end
end
The path to index action is
user_user_bookings_path or
/users/:user_id/user/bookings(.:format)
which works fine, but the double user_user sounds like a Catch 22 joke. Is there a more elegant way to do this?
What would you like to achieve? You are namespacing under "user" after all. You can try options like as: nil, but I think this will be even funnier (user__bookings_path).
What you can do is write every route by hand, something like:
resources :users do
post 'bookings', to: 'user/bookings#create'
end
# => user_bookings_path, POST /users/:user_id/bookings
or if you want to preserve the URL
resources :users do
post '/user/bookings', to: 'user/bookings#create', as: 'bookings'
end
# => user_bookings_path, POST /users/:user_id/user/bookings
Try this
resources :users do
resources :bookings
end
According to the docs you can namespace your resource
by using the namespace block
namespace :api do
resources :users
end
this would give you those routes:
/api/users [GET, POST]
/api/users/:id [GET, PUT, DELETE]
However you want to nest the resource within another resource (docs) you would do this:
resources :users do
resources :bookings
end
Which would result in these routes:
/users/:user_id/bookings [GET, POST]
/users/:user_id/bookings/:id [GET, PUT, DELETE]
Because you have your controller scoped under User you have to set the user scope like this:
resources :users do
resources :bookings, module: :user
end
Which results in those routes:
➜ playground rake routes
Prefix Verb URI Pattern Controller#Action
user_bookings GET /users/:user_id/bookings(.:format) user/bookings#index
POST /users/:user_id/bookings(.:format) user/bookings#create
new_user_booking GET /users/:user_id/bookings/new(.:format) user/bookings#new
edit_user_booking GET /users/:user_id/bookings/:id/edit(.:format) user/bookings#edit
user_booking GET /users/:user_id/bookings/:id(.:format) user/bookings#show
PATCH /users/:user_id/bookings/:id(.:format) user/bookings#update
PUT /users/:user_id/bookings/:id(.:format) user/bookings#update
DELETE /users/:user_id/bookings/:id(.:format) user/bookings#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
I have an issue regarding shallow routing in rails. I have a set of routes nested 3 levels users have many portfolios have many displays. What i want to do is have a shallow route for my portfolios, but have verbose routing for displays. I've tried passing shallow: false but that doesnt seem to do anything
# config/routes.rb
resources :users do
resources :portfolios, shallow: true do
resources :displays #shallow: false
end
end
for my users and portfolios, this works the way i want
#users routes
/users #index
/users/:id #show
#portfolios routes
/users/:user_id/portfolios #index
/portfolios/:id #show
however, from here i want verbose displays keyed off the shallow portfolio
#desired display routes
/portfolios/:portfolio_id/displays #index
/portfolios/:portfolio_id/displays/:id #show
#actual display routes
/portfolios/:portfolio_id/displays #index
/displays/:id #show
Is there a way to utilize the shallow configuration in this way?
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
resources :users do
resources :portfolios, shallow: true
end
resources :users, only: [] do
resources :portfolios, only: [] do
resources :displays
end
end
end
Here are the routes
Prefix Verb URI Pattern Controller#Action
user_portfolios GET /users/:user_id/portfolios(.:format) portfolios#index
POST /users/:user_id/portfolios(.:format) portfolios#create
new_user_portfolio GET /users/:user_id/portfolios/new(.:format) portfolios#new
edit_portfolio GET /portfolios/:id/edit(.:format) portfolios#edit
portfolio GET /portfolios/:id(.:format) portfolios#show
PATCH /portfolios/:id(.:format) portfolios#update
PUT /portfolios/:id(.:format) portfolios#update
DELETE /portfolios/:id(.:format) portfolios#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
user_portfolio_displays GET /users/:user_id/portfolios/:portfolio_id/displays(.:format) displays#index
POST /users/:user_id/portfolios/:portfolio_id/displays(.:format) displays#create
new_user_portfolio_display GET /users/:user_id/portfolios/:portfolio_id/displays/new(.:format) displays#new
edit_user_portfolio_display GET /users/:user_id/portfolios/:portfolio_id/displays/:id/edit(.:format) displays#edit
user_portfolio_display GET /users/:user_id/portfolios/:portfolio_id/displays/:id(.:format) displays#show
PATCH /users/:user_id/portfolios/:portfolio_id/displays/:id(.:format) displays#update
PUT /users/:user_id/portfolios/:portfolio_id/displays/:id(.:format) displays#update
DELETE /users/:user_id/portfolios/:portfolio_id/displays/:id(.:format) displays#destroy
I'm trying to make an app in Rails 5.
In order to keep the file structure neat, I'm trying to make folders inside my controllers directory, that I can use to group similar resources.
For example, I have:
app/controllers/users/users_controller.rb
I can then make my sessions controller nested inside the controllers/users director so that all resources relating to the user are grouped under the user folder.
I'm stuck though for what to do with my routes file.
When I rake routes, I can see:
users#index {:controllers=>{:users=>"users/users"}}
POST /users(.:format) users#create {:controllers=>{:users=>"users/users"}}
new_user GET /users/new(.:format) users#new {:controllers=>{:users=>"users/users"}}
edit_user GET /users/:id/edit(.:format) users#edit {:controllers=>{:users=>"users/users"}}
user GET /users/:id(.:format) users#show {:controllers=>{:users=>"users/users"}}
PATCH /users/:id(.:format) users#update {:controllers=>{:users=>"users/users"}}
PUT /users/:id(.:format) users#update {:controllers=>{:users=>"users/users"}}
DELETE /users/:id(.:format) users#destroy {:controllers=>{:users=>"users/users"}}
In my routes file, I've tried a few things (set out below) - none of them work:
Rails.application.routes.draw do
devise_for :users,
:controllers => {
:sessions => 'users/sessions',
:registrations => "users/registrations",
:omniauth_callbacks => 'users/omniauth_callbacks'
}
resources :identities,
:controllers => {
:identities => 'users/identities'
}
resources :users do
scope module: :users do
resources :users
end
end
root 'home#index'
end
I have also tried:
resources :users,
:controllers => {
:users => 'users/users'
}
Each time, I get an error that says:
ActionController::RoutingError at /users
uninitialized constant UsersController
I don't know what I need to do to get this working. I have changed each of my controllers that is nested inside the controllers/users folder with a prefix of:
Users::
Can anyone see how to set this up so that I can keep my files neatly organised?
Note: I haven't created the same file directory structure in my models folder. I want to - but I'm concerned that I'm not able to figure this out for the controllers. Can anyone see what I'm doing wrong?
I recommend you put the actual users_controller in the base controllers directory, and only put the nested controllers inside the users directory (ie follow the same structure as the nesting).
The alternative is to name the users_controller the way that rails is expecting ie inside the Users module:
module Users
class UsersController < ApplicationController
...
and then refer to it with: Users::UsersController
I always find the duplication in the name a bit cumbersome, and prefer top-level controllers to just be in the base directory.
I also really like the approach explained in this video:
https://youtu.be/1B0Vioz4Ukw
Basically he creates BaseController for each Module, those inherit from ApplicationController and then the related controllers inherit directly from their corresponding BaseController.
Example used in video
Controllers
Controllers are namespaced, in the example with Auth. Then a base class is made, derived from ApplicationController. The base class is then used for all other of the Auth controllers.
# app/controllers/auth/base_controller.rb
class Auth::BaseController < ApplicationController
end
# app/controllers/auth/posts_controller.rb
class Auth::PostsController < Auth::BaseController
...
end
# app/controllers/auth/sessions_controller.rb
class Auth::SessionsController < Auth::BaseController
...
end
# app/controllers/auth/users_controller.rb
class Auth::UsersController < Auth::BaseController
...
end
Routes
Resources are namespaced while simple routes have auth/ added to their routes.
# config/routes.rb
namespace :auth do
resource :confirmation
resource :session, only: [:create]
resources :users, only: [:create]
end
get 'login' => 'auth/sessions/new'
delete 'logout' => 'auth/sessions#destroy'
get 'register' => 'auth/users#new'
Views
Views are now namespaced under auth.
app/views/auth/sessions/*
app/views/auth/posts/*
app/views/auth/users/*
Paths
Paths will also be under auth namespace to work. Check rails routes for details.
Example route: auth_session_path
Example route from set of objects: [:auth, #user]
Is it possible to reference app/controllers/admin/categories_controller.rb using categories_path instead of admin_categories_path ?
I'm using Rails 4.
# app/controllers/admin
class Admin::CategoriesController < Admin::BaseController
end
# visiting localhost:3000/admin/categories causes route not found error 'admin/categories'
scope module: "admin" do
resources :categories
end
# visiting localhost:3000/admin/categories causes uninitialized constant CategoriesController
scope "/admin" do
resources :categories
end
I believe that you have to reference the controller at the resources
scope 'admin' do
resources :categories, controller: 'admin/categories'
end
so the routes became
categories GET /admin/categories(.:format) admin/categories#index
POST /admin/categories(.:format) admin/categories#create
new_category GET /admin/categories/new(.:format) admin/categories#new
edit_category GET /admin/categories/:id/edit(.:format) admin/categories#edit
category GET /admin/categories/:id(.:format) admin/categories#show
PATCH /admin/categories/:id(.:format) admin/categories#update
PUT /admin/categories/:id(.:format) admin/categories#update
DELETE /admin/categories/:id(.:format) admin/categories#destroy