👌
CanCanCan で少し複雑な権限管理
初めに
以前紹介したCMSに、よくある承認フローだったり、閲覧しかできないユーザ、他者が登録したのレコードに対する制限だったりの機能が必要になったため、備忘録としてまとめておきます。(いつもこの辺りで実装迷うので・・・)
ActiveAdmin + CanCanCan での権限管理
前提条件
- Rails 7.x 系
- 管理画面はActiveAdminを導入している
- 伴って、基本的にCanCanCanを使用する
- 複数コンテンツのレコードは同一テーブルで管理
- 参考CanCanCanの基本的な使い方
必要な機能
- コンテンツは管理画面から追加・削除が可能
- コンテンツごとに下記権限が必要
- 閲覧不可
- 登録可能
- 他者作成レコード操作可能
- 承認可能
テーブル構成
- コンテンツ(Content)
- ニュース、ブログ等コンテンツを管理するテーブル
id, name, created_at, updated_at
- ニュース、ブログ等コンテンツを管理するテーブル
- コンテンツレコード(ContentRecord)
- コンテンツのレコードを保持するテーブル
id, content_id, create_admin_user_id, body, status, created_at, updated_at
- コンテンツのレコードを保持するテーブル
- 管理者(AdminUser)
- ログインアカウント
id, email, password, role_id
- ログインアカウント
- 権限マスタ(Role)
- 権限マスタ
id, name, created_at, updated_at
- 権限マスタ
- 権限詳細(RoleDetail)
- コンテンツ毎の詳細を保持する子テーブル
id, role_id, content_id, content_role
- コンテンツ毎の詳細を保持する子テーブル
コード実装
models/ability.rbの設定
Contents.all.each do |c|
# コンテンツの権限詳細が設定されているかどうか
content_role = user.role.role_details.find_by(content_id: c.id)
next if content_role.blank?
case content_role
when :writer
can :create, Content, content_id: c.id # このコンテンツを登録可能
can [:read, :update, :delete], Content, content_id: c.id, create_admin_user_id: user.id # 自身のレコードの操作可能
when :manager
can :create, Content, content_id: c.id # このコンテンツを登録可能
can [:read, :update, :delete], Content, content_id: c.id # レコードの操作可能
when :approver
can :create, Content, content_id: c.id # このコンテンツを登録可能
can [:read, :update, :delete], Content, content_id: c.id # レコードの操作可能
end
end
これで、コンテンツ毎のライター、マネージャー、承認者権限の設定ができました。
ただこれではまだ承認フローが実装できていません。
CanCanCanでアクセス可能属性を設定することもできるようですが、自分の場合はコントローラにロジックを記載しました。
admin/content_records.rbの実装
form do |f|
〜
if approver? # ログインユーザがこのコンテンツの承認者かどうか判定
f.inputs do
f.input :status
end
end
〜
end
controller do
def create
unless approver? # 承認者以外の場合、 statusを除外しておく
params[:content_record].delete(:status)
end
super
end
def update
unless approver? # 承認者以外の場合、 statusを除外しておく
params[:content_record].delete(:status)
end
super
end
end
これで、承認者以外はstatusカラムを操作できなくなりました。
一旦これで、コンテンツ毎に4種類の権限を設定できるようになりました。
あとは role, role_details を管理する画面と、admin_userのroleを設定できるようにカスタマイズすれば、たったこれだけのコードで承認フロー、権限管理を導入することができました。
めでたしめでたし
おまけ
実際に実装した権限設定画面のSS
Discussion