PunditとCanCanCanの比較
こんにちは!メグミです!
今回は権限管理のgemについて調べたことを書きたいと思います!
Pundit と CanCanCan の2つが人気がありそうだったので、
比較をしてみました?
まずはそれぞれのgemの概要について、
Pundit
https://github.com/varvet/pundit
Githubには、
シンプルで堅牢でスケーラブルな認可システムを作ることができるgem
とあります。
CanCanCan
https://github.com/CanCanCommunity/cancancan
Githubには、
認可のロジックを一箇所に保持し、簡単にメンテナンスやテストができるgem
とあります。
ざっくり紹介するとこんな感じです。
次はそれぞれのポイントごとに比較をしてみます。
導入
Pundit
class ApplicationController < ActionController::Base
include Pundit
end
gemをインストールし、コントローラーでモジュールを include することで使用できる。
CanCanCan
gem をインストールし、Abilityクラス(※詳細は後述)を設置すれば使用可能。
コントローラーでモジュールをincludeをする必要はない。
権限の設定
以下2つのデータモデルに対する権限の設定の場合
- Post
- Dashboard
Pundit
class PostPolicy
attr_reader :user, :post
def initialize(user, post)
@user = user
@post = post
end
def update?
user.admin?
end
end
class DashboardPolicy
attr_reader :user, :dashboard
def initialize(user, dashboard)
@user = user
@dashboard = dashboard
end
def update?
user.admin?
end
end
各モデルに対応したPolicyファイルを作成し、権限ごとの設定を記述する。
CanCanCan
class Ability
include CanCan::Ability
def initialize(user)
can :read, Post, public: true
if user.admin?
can :update, Post
can :update, Dashboard
end
end
end
Abilityクラスを追加し、各モデルに対するすべての権限を記述する。
権限の認可
Pundit
def update
@post = Post.find(params[:id])
authorize @post
if @post.update(post_params)
redirect_to @post
else
render :edit
end
end
authorize メソッドを使うと、モデル(この場合Postモデル)に対応するPolicyクラス(この場合PostPolicy)が自動的に参照される。
class PostPolicy < ApplicationPolicy
def update?
user.admin?
end
end
コントローラーのアクション名(update)とマッチしたPolicyのメソッド(update?)が呼ばれ、そのアクションが実行可能か判定する。
CanCanCan
def update
@post = Post.find(params[:id])
authorize! :update, @post
end
authorize! メソッドで権限の認可ができる。
class Ability
include CanCan::Ability
def initialize(user)
can :read, Post, public: true
if user.admin?
can :update, Post
can :update, Dashboard
end
end
end
Abilityクラスに定義した権限設定を参照し、権限判定する。
権限の判定
Pundit
<% if policy(@post).update? %>
<%= link_to "Edit post", edit_post_path(@post) %>
<% end %>
policyメソッドを使用することで、権限判定することができる。
CanCanCan
<% if can? :update, @post %>
<%= link_to "Edit post", edit_post_path(@post) %>
<% end %>
can? や cannot? メソッドを使うことで、権限を判定することができる。
スコープ
Pundit
Pundit では Scope という概念
class PostPolicy < ApplicationPolicy
class Scope < Scope
def resolve
if user.admin?
scope.all
else
scope.where(published: true)
end
end
end
# 他のメソッド...
end
PolicyファイルにScopeクラスを定義することで特定のユーザーがアクセスできるレコードを制限できる。
def index
@posts = policy_scope(Post)
end
def show
@post = policy_scope(Post).find(params[:id])
end
policy_scope メソッドを使ってスコープを利用することができる。
CanCanCan
CanCanCan では Hash of Conditions という概念
can :read, Post, published: true
条件を渡すことで、取得するレコードを絞ることができる。
Post.accessible_by(current_ability)
モデルに対して、 accessible_by メソッドを使うことで、定義した条件のレコードを取得できる。
まとめ
Pundit
特徴
各モデルに対応したPolicyを設置し権限を設定
メリット
データモデルが多い場合でもPolicyファイルはシンプルに保つことができる。
デメリット
それぞれのPolicyファイルを確認しないと権限設定がわからないため、権限の全体が見通しづらい。
CanCanCan
特徴
Abilityクラスの中で各モデルクラスへの権限を設定
メリット
権限の設定はすべてAbilityクラスで定義されているため、権限の全体が理解しやすい。
デメリット
データモデルが多く複雑な権限体系の場合は大量の分岐処理が一つのクラスの中に記述されるため不向き。
さいごに
CarelyではPunditを採用しています!
CanCanCanについては全く知らなかったので勉強になりました!
iCAREでは仲間を募集中です!
興味がある方はこちらからエントリーお待ちしています?