WeBlog

Webに関する情報を中心に発信してるブログ

名前空間のルーティング、コントローラー、ビューを作成する方法

名前空間とは?

名前空間は、クラスをフォルダの構造のように、階層的に分類することが出来る仕組みのことになります。

同じフォルダの中だと、同じ名前のファイルは作れません。

でも、フォルダを別にしてしまえば、同じ名前のファイルを作ることが出来ます。

この仕組みと名前空間は考え方は同じです。

フォルダの中にファイルがあるのと同じように、違う名前空間で同じ名前のクラスを定義出来るようになります。

index.htmlというファイル作りたいけど、index.htmlファイルはすでに存在するから、じゃあフォルダを分けてあげればindex.htmlファイル作れるじゃんという感じです。

同じクラス名を違う名前空間であれば複数作ることができます。

当然、名前空間の中に名前空間を作ることもできます。

フォルダの中にフォルダを作成しているの同じです。

名前空間のコントローラーのみを作成する

# rails g controller 名前空間名::コントローラー名

% rails g controller Admin::Base

      create  app/controllers/admin/base_controller.rb
      invoke  erb
      create    app/views/admin/base
      invoke  decorator
      create    app/decorators/admin/base_decorator.rb

名前空間の中にコントローラーを作成してみます。

名前空間の中にコントローラーを作成するには、rails g controller 名前空間名::コントローラー名という形でコマンドを打ちます。

作成されたファイルやフォルダをみてみると、app/controllers/adminの中にコントローラーが作成されています。

# app/controllers/admin/base_controller.rb

class Admin::BaseController < ApplicationController
end

実際に作成されたコントローラーを確認してみます。

上記のようにコントローラー名の前にAdmin::とついています。

これは、rails g controller Admin::Baseとコマンドを打ったからです。

これが名前空間名::名前空間のキーワードになります。

名前空間のコントローラー、アクション、ルーティング、ビューを作成してみる

# rails g controller 名前空間名::コントローラー名 アクション名

% rails g controller Admin::User_sessions new create destroy

      create  app/controllers/admin/user_sessions_controller.rb
       route  namespace :admin do
  get 'user_sessions/new'
  get 'user_sessions/create'
  get 'user_sessions/destroy'
end
      invoke  erb
      create    app/views/admin/user_sessions
      create    app/views/admin/user_sessions/new.html.erb
      create    app/views/admin/user_sessions/create.html.erb
      create    app/views/admin/user_sessions/destroy.html.erb
      invoke  decorator
      create    app/decorators/admin/user_session_decorator.rb

次に名前空間を使って「コントローラー」「アクション」「ルーティング」「ビュー」を一括で作成してみます。

そうすると、コントローラーは

app/controllers/admin/user_sessions_controller.rb

という形でadminというフォルダの中にコントローラーが作成されました。

# /admin/user_sessions_controller.rb

class Admin::UserSessionsController < ApplicationController
  def new
  end

  def create
  end

  def destroy
  end
end

中身は上記にようになっています。

今までと違うのは名前空間名がコントローラー名の前についているかどうかだけです。

# config/routes.rb

Rails.application.routes.draw do
  namespace :admin do
    get 'user_sessions/new'
    get 'user_sessions/create'
    get 'user_sessions/destroy'
  end

# ルーティングの表
admin_user_sessions_new GET    /admin/user_sessions/new(.:format)               admin/user_sessions#new
admin_user_sessions_create GET    /admin/user_sessions/create(.:format)         admin/user_sessions#create
admin_user_sessions_destroy GET    /admin/user_sessions/destroy(.:format)       admin/user_sessions#destroy                                                                admin/user_sessions#destroy

次にルーティングを確認してみます。

上記のようになります。

ルーティングもnamespace :admin という枠で囲われています。

これが名前空間の中のルーティングを表します。

ルーティングの表をみてみても、/admin/user_sessions/newという形で/adminから始まっています。

割り振るコントローラー#アクションもadmin/user_sessions#newという形でadminから始まっています。

f:id:weblog_tec:20210505223403p:plain

画像で確認すると上記のような階層になります。

また、ビューファイルもapp/views/admin/user_sessions/new.html.erbのように

adminというフォルダの中に作成されます。

どんな時に名前空間を使うのか?

# app/controllers/user_sessions_controller.rb

class UserSessionsController < ApplicationController
  skip_before_action :require_login, only: %i[new create]

  def new; end

  def create
    @user = login(params[:email], params[:password])
    if @user
      redirect_back_or_to boards_url, success: t('.success')
    else
      flash.now[:danger] = t('.fail')
      render :new
    end
  end

  def destroy
    logout
    redirect_to root_url, success: t('.success')
  end
end

例えば一般ユーザー用のログインのためのUserSessionsControllerがあったとします。

# app/controllers/admin/user_sessions_controller.rb

class Admin::UserSessionsController < Admin::BaseController
  skip_before_action :require_login, only: %i[new create]
  skip_before_action :check_admin, only: %i[new create]
  layout 'layouts/admin_login'

  def new; end

  def create
    @user = login(params[:email], params[:password])
    if @user
      redirect_to admin_root_path, success: t('.success')
    else
      flash.now[:danger] = t('.fail')
      render :new
    end
  end

  def destroy
    logout
    redirect_to admin_login_path, success: t('.success')
  end
end

もう1つ管理者専用のログインも一般ユーザーとは別で作成したいと思います。

管理者専用のログインフォームもUserSessionsControllerという名前にしたいですが、すでに一般ユーザーでUserSessionsControllerはあります。

そうすると名前が被るのでUserSessionsControllerは作成できないです。

(同じフォルダに同じ名前のファイルは作成できない)

そんな時に名前空間で分けてあげれば、同じ名前のUserSessionsControllerを作成することができます。

名前空間で分けることで、adminフォルダ配下は管理者用のコントローラーだと一眼でわかります。

また、管理者用のいろんなコントローラーはApplicationControllerを継承するのではなく、管理者専用の継承元のコントローラー(Admin::BaseController)を作成してあげれば、そいつを継承して、ApplicationControllerに記載しているメソッドなどをオーバーライドすることで、管理者は管理者で分けることができます。

【 一般ユーザー 】

〇〇Controller < ApplicationController

一般ユーザーはそのままviews/layouts/ApplicationControllerを継承する。

【 管理者 】

Admin::△△Controller < Admin::BaseController < ApplicationController

管理者はviews/layouts/ApplicationControllerを直接継承するのではなく、間にAdmin::BaseControllerなどを挟んであげる。

そうすれば、Admin::BaseControllerApplicationControllerに記載したメソッドなどをオーバーライドできる。

さらに管理者だけで使うメソッドなどはAdmin::BaseControllerに書けば、一般ユーザーのコントローラーには影響がない。ということです。

https://railsguides.jp/routing.html#コントローラの名前空間とルーティング

https://railsguides.jp/routing.html#リソースフルルーティングをカスタマイズする