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