Railsアプリケーションで利用可能な認可gemであるaction_policyの機能を紹介します。
ここでは類似したパラダイムで構成されるpunditと比較しながら説明していきます。
他にはcancancan gemも有名ではありますが、こちらとの比較は既存記事の「Authorization in Rails controllers: Pundit versus CanCan」などに譲ります。
punditとaction_policy
punditとaction_policyの機能はかなり近しいです。action_policyがpunditを参考にしているため当然の話ではあります。
action_policy自身は「punditで必要とされていたHACKがaction_policyになった」と主張しており、これが両者の差異になります。
以下、細かい話ですが例を二つご紹介します。
namespaceの推論
action_policyではPolicyのnamespaceを推論することができます。
Namespaces — Action Policy: authorization framework for Ruby/Rails applications
module Admin
class UsersController
一方でpundtiでは呼び出し時に明示的な指定が必要です。
Policy Namespacing — varvet/pundit: Minimal authorization through OO design and pure Ruby classes
authorize(post) # => will look for a PostPolicy
authorize([:admin, post]) # => will look for an Admin::PostPolicy
authorize([:foo, :bar, post]) # => will look for a Foo::Bar::PostPolicy
policy_scope(Post) # => will look for a PostPolicy::Scope
policy_scope([:admin, Post]) # => will look for an Admin::PostPolicy::Scope
policy_scope([:foo, :bar, Post]) # => will look for a Foo::Bar::PostPolicy::Scope
認可対象名とPolicyクラス名の不一致の処理
例として、以下のように注文(Order)をキャンセルするためのコントローラーを作成し、このアクションをリクエストするボタンをViewで実装することにします。
class Orders::CancelsController
punditで実装する場合、まず以下のようなPolicyクラスを作成します。
class Orders::CancelPolicy
punditでは、このように認可対象とクラス名が一致していないPolicyについて、Viewから呼び出すためのインターフェースが若干弱いです。
通常であれば #policy というヘルパーメソッドを利用できます。
しかし、このメソッドを通じて Orders::CancelPolicy のロジックを呼び出すことができません。
単にPolicyを呼び出すだけであれば、 Orders::CancelPolicy.new とすれば可能です。
ただし、punditにはPolicyインスタンスのキャッシュという機能があり、 #policy メソッドを経由せずに作成されたインスタンスにはこのキャッシュが効きません。
キャッシュが効かないから致命的ということはないのですが、用意されたインターフェースを利用しないためにパフォーマンス上の恩恵を受けられず、HACKのような実装になってしまいます。
一方、action_policyにはAuthorization Contextという、その名の通り認可コンテキストを指定する機能が存在します。
Policyクラスを作成するときにこのコンテキストを指定します。
class Orders::CancelPolicy
Viewからは allow_to? ヘルパーメソッドの with: オプションを指定することで、Policyクラスのロジックを呼び出すことができます。
これは素直な呼び出し方に見えますし、punditと違ってPolicyインスタンスのキャッシュも効きます。
punditで微妙に手が届かない箇所をカバーする一例として紹介しました。
その他、punditとの差分内容についてはaction_policyの公式ドキュメントをご参照ください。
個人的には、action_policyで不満足なことがないため、認可gemにはこちらを採用するようになりました。
元の記事を確認する