pundit Gemの使い方
pundit Gemの使い方
[pundit]Gemは、ユーザーの権限の条件によって表示できるビューを変えるもの
[pundit]Gemの使い方は、以下のようになる
[Gemfile]に以下のように記述
[Gemfile] gem "pundit"
↓
[application_controller.rb]に以下を記述する
[app/controllers/application_controller.rb] include Pundit
↓
以下コマンドで[policy]ファイルを生成する
$ rails g pundit:install
↓
上記で生成された[app/policies/application_policy.rb]を承継するように新規ファイルを作成し以下のようなクラスを定義する
[app/policies/user_policy.rb] class UserPolicy < ApplicationPolicy def index? true end def show? true end def create? user.admin? end def update? user.admin? || user == record end def destroy? user != record && create? end end
下記のようなコントローラーがある場合
[app/controllers/admin/users_controller.rb] class Admin::UsersController < ApplicationController layout 'admin' before_action :set_user, only: %i[show update destroy] def index authorize(User) # authorizeに引数で渡すモデルのオブジェクトが無い場合は、モデルをそのまま渡す @users = User.all.order(:id) end def show authorize(@user) # authorizeに引数で渡すモデルのオブジェクトがある場合は、そのオブジェクトを渡す end def create authorize(User) @user = User.new(user_params) if @user.save redirect_to admin_user_path(@user) else render :new end end def update authorize(@user) if @user.update(user_params) redirect_to admin_user_path(@user) else render :show end end def destroy authorize(@user) @user.destroy! redirect_to admin_users_path end private def user_params params.require(:user).permit(policy(:user).permitted_attributes) end def set_user @user = User.find(params[:id]) end end
createアクションは、authorize(User)により[app/policies/user_policy.rb]のcreate?アクションの(true or false)を確認する
今回は、userが管理者の場合はtrueを返しそのままcreateアクションが実行されるが管理者以外の場合はfalseになりcreateアクションが実行されず、通常のビューがブラウザに返らずPundit::NotAuthorizedErrorの例外が出る
↓
以下の記述をする事で、[Pundit::NotAuthorizedError]例外を403のHTTPステータスにできる
[config/application.rb] config.action_dispatch.rescue_responses["Pundit::NotAuthorizedError"] = :forbidden
上記を記述せずに権限が無いページにアクセスすると[categories]htmlファイルが500エラーになる
上記を記述すると権限が無いページにアクセスすると[categories]htmlファイルが403エラーになる
↓
下記のように記述することで、[user_not_authorized]メソッドで403のエラーページになった際の動きを定義できる
[app/controllers/application_controller.rb] class ApplicationController < ActionController::Base include Pundit rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized private def user_not_authorized flash[:alert] = "You are not authorized to perform this action." redirect_to(request.referrer || root_path) end end
また、画面全部ではなくユーザーの権限の状況によって表示したい部分を変えたい場合(権限の条件によって表示したいリンクと表示したくないリンクなど)がある場合は、ビュー側でpolicyヘルパーを使って以下のように記述できる
[app/views ファイル] <% if policy(user).index? %> <%= link_to users_path, "ユーザー一覧"%> <% end %>
上記は、UserPolicyのindex?メソッドの(true or false)の結果でリンクを表示したり表示しなかったりなどできる
※ポイント
[policy]ファイルは、クラスの最後にPolicyをつける
[pundit]の[policy]ファイルの中のuserという記述は、current_userメソッドが呼び出される
[app/policies/application_policy.rb]のrecordは、認可をチェックしたいモデルオブジェクトの事。
参考記事: