Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 5 - nested controllers with routes

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?

like image 927
Mel Avatar asked Dec 24 '22 01:12

Mel


2 Answers

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.

like image 196
Taryn East Avatar answered Dec 29 '22 12:12

Taryn East


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]

like image 21
Sebastian Delgado Avatar answered Dec 29 '22 10:12

Sebastian Delgado