はじめに
ブログアプリでタグ・著者・カテゴリーを作成する機能があります。ユーザー権限の種類は下記の3つです。
- admin
- editor
- writer
現状、writer権限のユーザーだけ各項目の作成権限が付与されていません。しかし各項目の一覧表示や編集・削除はできてしまいますので、それらもできないように変更しましょう。 また、writer権限ユーザーが権限を許可されていないページにアクセスした場合、403エラー画面が出るように変更しましょう。
Punditの導入
$ gem "pundit"
bundle install
し、
class ApplicationController < ActionController::Base
include Pundit
end
generatorを使います。
$ rails g pundit:install
app/policies/application_policy.rb
が生成されました。
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record) # こちらのuserはデフォルトでcurrent_userが引数に割り当てられるようになっている。recordの方には対応するモデルのインスタンスを手動で割り当てる。
@user = user
@record = record
end
def index?
false
end
------一部省略-------
end
このファイルで定義されるクラスApplicationPolicy
を継承して、コントローラーごとの認可ルールを記述していきます。
policyファイルの設定
今回権限を調整したいTag
, Author
, Category
モデルはSTI(単一テーブル継承)なので、継承元のTaxonomy
モデルに対してpolicyを作成しましょう。
class TaxonomyPolicy < ApplicationPolicy
def index?
user.admin? || user.editor?
end
def create?
user.admin? || user.editor?
end
def update?
user.admin? || user.editor?
end
def destroy?
user.admin? || user.editor?
end
end
モデル名_policy.rb
でファイルを作成モデル名Policy
でクラス名を定義def アクション名?
で認可ルール(policy)を記述def アクション名?
の返り値によって、認可するか否かを判断しています。 falseが返ってくれば、対応するコントローラのアクションは拒否されて、Pundit::NotAuthorizedError
が投げられます。
policyファイルを適用するには、コントローラ側からPunditを呼び出しましょう。
class Admin::TagsController < ApplicationController
def index
@tags = Tag.all.order(:slug)
authorize(Tag) # インスタンスモデルを利用しない(policy側ではuserの情報のみ扱う)場合に限り、authorize(Tag) という記述が可能。
@tag = Tag.new
end
-----------一部省略------------------
end
エラー画面設定
任意の403エラーページpublic/403.html
を作成します。
開発環境で403エラーページを表示させる
config/application.rbに追記
config.action_dispatch.rescue_responses["Pundit::NotAuthorizedError"] = :forbidden
この記述により、Production環境でユーザー向けの静的ページを表示させることができます。
なぜなら、config/envirronments/production.rb
の中のconfig.consider_all_requests_local
がfalse
に設定されているため、エラーの詳細情報ではなく静的ページを表示する挙動になります。
ローカル開発環境で静的ページを確認する場合は、config/environments/development.rbのconfig.consider_all_requests_local
をfalse
にして、サーバー再起動してください。
[コラム] 共通レイアウトをエラーページに表示させる場合
共通ヘッダーなどのレイアウトも表示させる場合は、Applicationcontrollerでrescue
処理を記載して、app/view以下にテンプレートファイルを用意してrender
を使って表示させます。
class ApplicationController < ActionController::Base
include Pundit
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
private
def user_not_authorized
render 'error/403', status: :forbidden
end
end
参考記事

コメント