プログラミング学習 備忘録

Railsを学習していく上での技術メモ。学んだことや解決したエラーなどを記録していきます。

Admin-LTE3を使用した管理画面の実装②(新しい知識と学んだ事)

今回の実装を通して学んだことをまとめていきます



◆Userに権限を付与する

一般ユーザーと管理者ユーザーを分けるために、Usersテーブルに、roleという名前のカラムを作成する。(名前はわかればなんでもおk)

データ型はintegerにして、enumオプションを使用し「0: 一般、1: 管理者」という風に別名をつける。

#migrationファイル内
class AddRoleToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :role, :integer, default: 0, null: false, limit: 1
#defaultを一般ユーザーの0に設定し、limitを1にすることで、ユーザーは0 or 1の2種類に振り分けられる。
  end
end
#User.rb内
  enum role: 
  {
    general: 0,
    admin: 1
  }
#enumオプションを使うことで、0,1という数字の代わりにgeneralとadminという属性をUserに持たせる事ができる。
end




◆管理画面用のコントローラーを作成する

Admin関連のコントローラーは、admin/というディレクトリで一括管理した方が保守性が高いため、adminというnamespaceで区切ってコントローラーを作成するとよい。

rails g controller admin/base
rails g controller admin/user_sessions
rails g controller admin/dashboards

また、admin/user_sessionsコントローラーと、admin/dashboardsコントローラーはadmin/baseコントローラーを継承するように設定する。
こうすることで、admin関連のページ全体で使用したいメソッドやbefore_actionなどをbaseコントローラーに定義することで全てのコントローラーに適用されるようになる。

class Admin::UserSessionsController < Admin::BaseController
class Admin::DashboardsController < Admin::BaseController 




◆namespaceを使ったURL設定

URLもコントローラー同様、adminというネームスペースを使用して一般画面とは切り離すと良い。

ネームスペースを使用することで普通にルーティングしたときと比べてどのような違いがあるのかについては、こちらのQiita記事を参考にさせていただきました。
Railsのroutingにおけるscope / namespace / module の違い - Qiita

  namespace :admin do
    get '/login', to: 'user_sessions#new'
    post '/login', to: 'user_sessions#create'
    delete '/logout', to: 'user_sessions#destroy'
    root 'dashboards#index'
  end

こうすることで、ルーティングが以下のようになり、path,URL,コントローラー全てをadminというネームスペースで切り分ける事ができる。

            admin_login GET    /admin/login(.:format)                                                                   admin/user_sessions#new
                          POST   /admin/login(.:format)                                                                   admin/user_sessions#create
             admin_logout DELETE /admin/logout(.:format)                                                                  admin/user_sessions#destroy
               admin_root GET    /admin(.:format)                                                                         admin/dashboards#index

URLもコントローラー同様、adminというネームスペースを使用して一般画面とは切り離すと良い。

ネームスペースについてはこちらのQiita記事を参考にさせていただきました。 Railsのroutingにおけるscope / namespace / module の違い - Qiita

  namespace :admin do
    get '/login', to: 'user_sessions#new'
    post '/login', to: 'user_sessions#create'
    delete '/logout', to: 'user_sessions#destroy'
    root 'dashboards#index'
  end

こうすることで、ルーティングが以下のようになり、path,URL,コントローラー全てをadminというネームスペースで切り分ける事ができる。

            admin_login GET    /admin/login(.:format)                                                                   admin/user_sessions#new
                          POST   /admin/login(.:format)                                                                   admin/user_sessions#create
             admin_logout DELETE /admin/logout(.:format)                                                                  admin/user_sessions#destroy
               admin_root GET    /admin(.:format)                                                                         admin/dashboards#index

URLもコントローラー同様、adminというネームスペースを使用して一般画面とは切り離すと良い。

ネームスペースについてはこちらのQiita記事を参考にさせていただきました。 Railsのroutingにおけるscope / namespace / module の違い - Qiita

  namespace :admin do
    get '/login', to: 'user_sessions#new'
    post '/login', to: 'user_sessions#create'
    delete '/logout', to: 'user_sessions#destroy'
    root 'dashboards#index'
  end

こうすることで、ルーティングが以下のようになり、path,URL,コントローラー全てをadminというネームスペースで切り分ける事ができる。

            admin_login GET    /admin/login(.:format)                                                                   admin/user_sessions#new
                          POST   /admin/login(.:format)                                                                   admin/user_sessions#create
             admin_logout DELETE /admin/logout(.:format)                                                                  admin/user_sessions#destroy
               admin_root GET    /admin(.:format)                                                                         admin/dashboards#index

URLもコントローラー同様、adminというネームスペースを使用して一般画面とは切り離すと良い。

ネームスペースについてはこちらのQiita記事を参考にさせていただきました。 Railsのroutingにおけるscope / namespace / module の違い - Qiita

  namespace :admin do
    get '/login', to: 'user_sessions#new'
    post '/login', to: 'user_sessions#create'
    delete '/logout', to: 'user_sessions#destroy'
    root 'dashboards#index'
  end

こうすることで、ルーティングが以下のようになり、path,URL,コントローラー全てをadminというネームスペースで切り分ける事ができる。

            admin_login GET    /admin/login(.:format)                                                                   admin/user_sessions#new
                          POST   /admin/login(.:format)                                                                   admin/user_sessions#create
             admin_logout DELETE /admin/logout(.:format)                                                                  admin/user_sessions#destroy
               admin_root GET    /admin(.:format)                                                                         admin/dashboards#index




◆User_sessionsコントローラーの書き方

最初はcreateアクションをこのようにコーディングしていた。

  def create
    @user = login(params[:email], params[:password])

    if @user.present? && @user.admin?
      flash[:success] = 'ログインしました'
      redirect_to admin_root_path
    elsif @user.present? && @user.general?
      flash[:danger] = '権限がありません'
      redirect_to root_path
    else
      flash[:danger] = 'ログインに失敗しました'
      redirect_to admin_login_path
    end
  end

elsifを使っているので条件分岐が3つになり、コードが少々冗長になっている。
しかし、実際には管理画面全体をAdminオンリーで制限をかけるので、AdminかGeneralかの判定はBase_controllerのbefore_actionで定義した方が良い。

修正後のコードがこちら

class Admin::BaseController < ApplicationController
  before_action :check_admin
  layout 'layouts/admin_application'

# layoutで、admin_applicationを明示的に指定する事で、管理画面全体にadmin_application.html.erbがデフォルトで適用される。

  private

  def not_authenticated
    flash[:warning] = t('defaults.message.require_login')
    redirect_to admin_login_path
  end

  def check_admin
    redirect_to root_path, warning: t('defaults.message.not_authorized') unless current_user.admin?
  end
end
class Admin::UserSessionsController < Admin::BaseController
  skip_before_action :check_admin, only: %I[new create]
  skip_before_action :require_login, only: %I[new create]
  layout 'layouts/admin_login', layout: false

# ログインページのみ、ヘッダーやフッター、サイドバーのないシンプルなフォームにするためlayout: falseでadmin_application.html.erbが適用されないように設定している。
  
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




◆知識


admin_login.html.erb内に<%= csrf_meta_tags %>の記述がないとInvalid Authentication Tokenエラーが出る。

同様に、admin_application.html.erb内に<%= csrf_meta_tags %>の記述がないと、destroyアクションが正しく機能しない。

Rails-ujsをマニフェストファイルで読み込んでいないと、postリクエストやdeleteリクエストが正しく動作せず、全てgetリクエストになってしまう。

Rails-ujsの役割については下記の記事を参考にさせていただきました
Rails学習者にrails-ujsの動作説明したら感動された話 - INODEVLOG