Pundit 権限管理

2021.5.24

応用編6

<現在>

Punditは入っている

<目標>

権限設定の記述を見つけ、ライターにタグ・著者・カテゴリーの一覧表示・編集・削除を出来ないようにする。

権限エラーが発生した際に、403エラーのページを表示させる(403.htmlは、public配下に新たに作成する)

  Pundit gem

各権限管理

リソースに対して、どのユーザーであれば処理が許可されるのかを定義する。

参照

pundit/README.md at master · varvet/pundit · GitHub

<流れ>

(app/polices/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

def show?
false
end

def create?
false
end

def new?
create?
end

def update?
false
end

def edit?
update?
end

def destroy?
false
end

def scope
Pundit.policy_scope!(user, record.class)
end

class Scope
attr_reader :user, :scope

def initialize(user, scope)
@user = user
@scope = scope
end

def resolve
scope
end
end
end

 

今回の権限をつけたい部分が、STIなので、ここにまとめて作成する。

モデル名_policy.rbでファイル作成

モデル名Policyでクラス名を定義

def アクション名?で認可ルール(policy)を記述

def アクション名?の返り値によって認証するか判断している。falseだとアクションは拒否されて、Pundit::NotAuthorizedErrorが投げられる。

||」について参照

演算子式 (Ruby 3.0.0 リファレンスマニュアル)

(app/polices/taxonomy_policy.rb) 

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

 

403エラーページを表示する

2つ方法がある。

GitHub - varvet/pundit: Minimal authorization through OO design and pure Ruby classes

❶config/application.rbに↓を記述(今回)

config.action_dispatch.rescue_responses["Pundit::NotAuthorizedError"] =
:forbidden

(public/403.html.erb)

<!DOCTYPE html>
<html>
<head>
<title>Forbidden(403)</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
</head>

<body>
<p>このページへのアクセス権限がありません。</p>
</body>
</html>

❷rescue_fromメソッドを使用して例外処理を記述する

ポイント

❶ヘッダーやフッターの共有ページについて

・今回はpublic以下の静的なページを表示させる為、ヘッダーやフッターの共有ページは不要。

・共通のヘッダー等のレイアウトを表示させたい場合は、Controllerでrescue処理を記載し、renderまたはredirect_toでapp/views以下のテンプレートファイルを表示させる。

❷開発環境で403エラーページを表示させるか

rescue処理をする場合は、if Rails.env.production?などの制限がないと開発中に他の機能で権限エラーが発生した時に、開発用のエラーページが表示されなくなってしまう。

今回のように、config/application.rbへの記載であれば、development.rbconfig.consider_all_requests_localtrueであるProduction環境のみに静的ページを表示することができる。

もし実装できているか確認する際は、development.rbconfig.consider_all_requests_localfalseにしてwriterでloginし、確認すると表示される。

 

 参照

config.consider_all_requests_local | Railsドキュメント

【Rails5】rescue_fromによる例外処理:アプリ固有のエラーハンドリングとエラーページ表示 - Qiita

 

 

RSpec

driven_by(:rake_test)でステータスコードをテストする

これがないと、この後の、have_http_status()「Capybara::NotSupportedByDriverError:Capybara::Driver::Base#status_code」というエラーになる

before do
driven_by(:rake_test)
end

 

ステータスコードについて

参照

ステータスコードとは?今さら聞けないステータスコードの基礎知識 | SEO研究所サクラサクラボ

 

 

初めて使用した

参照

使えるRSpec入門・その4「どんなブラウザ操作も自由自在!逆引きCapybara大辞典」 - Qiita

(公式)

`have_http_status` matcher - Matchers - RSpec Rails - RSpec - Relish

 

 

have_http_status()

レスポンスのステータスコードを検証する

driven_by(:rake_test)を使用しないとエラーになるので注意!

expect(page).to have_http_status(403), 'ライターがカテゴリー
編集ページのアクセスに成功しています'

 

 hsve_selector

特定のタグやCSS要素、IDに特定の文字列が表示されていることを検証する

expect(page).not_to have_selector("input[value=#{category.name}]")

 HTML

<input class="form-control" type="text" value="1">