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
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
@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による権限管理 [俺の備忘録]