前回の【Activeadmin超入門】インストール・環境設定 〜その1〜 - とーますメモに続けて、権限管理を行うためのCanCanCanの設定を書いていく。
前の記事にも書いたとおり、CanCanCanはCanCanの後継プロジェクトであり、
設定の仕方はCanCanと同じように記述できるっぽい。(違ったら教えて。)
ちなみに権限を設定する場合、以下の2つのケースがあると思う。
1)1ユーザに、1つの権限を付与
2)1ユーザに、複数の権限を付与
それぞれの場合で、どのように設定するかをメモ書き。
また権限は「admin」と「manager」の2つとする。
1)1ユーザに、1つの権限を付与
①DB変更
まずは下準備に、権限を保存するカラムをdeviseが作成する"admin_users"テーブルに追加する。権限を保存するカラムとして、roleを追加する。このカラムの値のバリエーションはそこまで沢山無いため、データ型はEnumにする。
$ bundle exec rails g migration add_role_to_admin_users role:integer
生成されたマイグレーションファイルに「null: false, default: 2, :after => :encrypted_password」を追加。
自分はカラムの位置も気にするので、encrypted_passwordの後にroleカラムを配置。
class AddRoleToAdminUsers < ActiveRecord::Migration[5.1] def change add_column :admin_users, :role, :integer, null: false, default: 2, :after => :encrypted_password end end
そしてマイグレーション
$ bundle exec rake db:migrate
②Enum設定
models/admin_user.rbで「enum role: { admin: 1, manager: 2 }」を追加
class AdminUser < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable enum role: { admin: 1, manager: 2 } end
③Abilityクラスの生成
CanCanCanでは権限設定をこのAbilityクラスで行う。
生成方法は以下
$ bundle exec rails g cancan:ability
生成されたability.rbに[admin]と[manager]の権限設定を行う。
以下の例はadminには全権限を与え、
managerには、dashboardページには全権限を与え、
AdminUserページには読込権限のみを与える設定。
app/models/ability.rb
class Ability include CanCan::Ability def initialize(admin_user) admin_user ||= AdminUser.new if admin_user.admin? can :manage, :all elsif admin_user.manager? can :manage, ActiveAdmin::Page, :name => "Dashboard" can :read, AdminUser end end end
ロールに付与できる権限の基本は5つ。
「create、read、update、destroy、manage」
manage以外は、名前の通りの意味。
manageは「CRUD全て」という意味ではないらしく、
独自で設定した権限も含めての全権限という意味らしい。。。(あってるかな?)
詳細は以下のサイト様より。
How to use CanCan / CanCanCan - Qiita
また権限設定は順番が大事で、競合する設定がある場合
最後に適用されたほうが有効になるっぽい。
ちなみに権限にはエイリアスも設定できる。デフォルトでは以下の設定がされている。
alias_action :index, :show, :to => :read alias_action :new, :to => :create alias_action :edit, :to => :update
一行目の例で行くと、:indexや:showという権限も:readとして使用できるということだろう。
※[Note] ちなみにactiveadminで作成できるページの種類は、以下の2つ。
1)モデルに紐付いたページ(例:AdminUserページ) 2)モデルに紐付いていない独立したカスタムページ(例:Dashboard)
④current_ability関数のオーバーライド
Abilityクラスのinitializeはコントローラ上に定義された
current_abilityメソッドによって呼び出されるため、
必要に応じて適切な設定をする必要がある。
CanCanCanはcurrent_abilityのデフォルト処理では
現在ログインしているユーザ情報を"current_user"から取得する設定になっているが
activeadminインストール時に、deviseを一緒にインストールすると
ユーザを管理するモデルがAdminUserになるため、現在ログインしているユーザ情報は
"current_user"ではなく"current_admin_user"に入っている。
そのため、current_abilityメソッドの中身を以下のように変更する必要がある。
class ApplicationController < ActionController::Base protect_from_forgery with: :exception def current_ability # before # @current_ability ||= Ability.new(current_user) # after @current_ability ||= Ability.new(current_admin_user) end
⑤CanCanCanの有効化し、認証されたかった場合のメソッド定義
active_adminの設定ファイル内でCanCanCanを有効化する。
ActiveAdmin.setup do |config| ... config.authorization_adapter = ActiveAdmin::CanCanAdapter config.cancan_ability_class = "Ability" config.on_unauthorized_access = :access_denied ... end
1行目でCanCanCanを有効化し、
2行目でCanCanCanの権限管理クラス名を指定し
3行目で認証されなかった場合の処理を行うメソッドを指定する。
認証されたかった場合のメソッド定義(access_denied)は、application_controller.rbに記述
def access_denied(exception) # 権限がなくてアクセスできないページはダッシュボードへ飛ばしてメッセージを表示 # 認証が切れてアクセスできない場合はログイン画面を表示 if current_admin_user redirect_to admin_root_path, alert: I18n.t('active_admin.access_denied.message') else redirect_to new_admin_user_session_path, alert: exception.message end end
⑥AdminUserのindex及びformブロックにrole情報を入れる
自分は以下のように設定した。
app/admin/admin_user.rb
ActiveAdmin.register AdminUser do permit_params :email, :password, :password_confirmation, :role index do selectable_column id_column column :role column :email column :current_sign_in_at column :sign_in_count column :created_at actions end filter :email filter :current_sign_in_at filter :sign_in_count filter :created_at form do |f| f.inputs "Admin Details" do f.input :email f.input :password f.input :password_confirmation f.input :role, as: :radio, :collection => [ ['Admin', 'admin'], ['Manager', 'manager'] ] end f.actions end end
具体的に追加したのは、
(1)permit_paramsに:roleを追加
(2)indexブロックにcolumn :roleを追加
(3)formブロックにf.input :role...を追加
以上でユーザの追加・編集及び権限管理もできるようになる。
[参考記事]
How to use CanCan / CanCanCan - Qiita
【Rails】ActiveAdmin+CanCanCanで権限毎に色々したい - Qiita
CanCanCanを使ってみる - Qiita
Rails4でCanCanCanによる権限管理 [俺の備忘録]
2)1ユーザに、複数の権限を付与
CanCanCanの設定は1)と似ているが
それ以外が結構違う。
詳細は以下のサイトさんが詳しいので参照されたし。