#はじめに
active adminを使用して、管理画面を作った際にcurrent_userの権限に応じてviewを出し分ける。
という一見簡単そうな要件を実装するのに思いがけず時間を取られた(調査に時間かかったorz)ので、備忘録も兼ねてまとめておきたいと思います。
#そもそも、権限つけるならcancancan使えば良いんじゃないの?
cancancanを使えば、viewの出し分けは簡単に実装できるのですが、今回自分がやりたい要件にはcancancanはtoo muchなのと、管理画面のためのmodelが増えるのは嫌だったので、cancancanは使わずに実装することになりました。
(ほんとは管理アプリケーションと、サービスのアプリケーションは違うサーバーに実装したかった。。。)
#準備
active adminの導入は、いろんな方がすでに書いているので省略させていただきます。僕が実装した時はこの記事を参考にしたと思います。
https://qiita.com/yutackall/items/2b16d1ac2bd64dedd16e
current_userの権限を見てviewの出し分けをするのが目的なので、User modelにroleカラムを追加します。
rails enumについてはこちらが参考になると思います。
https://qiita.com/shizuma/items/d133b18f8093df1e9b70
userはサービスを利用する一般ユーザー、administratorは管理者、staffは管理者よりカジュアルな権限を持つ人とします。
{ user: '一般ユーザー', administrator: 'マネージャー', staff: '社員' }とでも思って下さいw
class User < ApplicationRecord
#enum の設定をします
enum role: [ :user, :administrator, :staff]
...
...
end
これでUserに権限のフラグをつけることができました。
#サンプルコード
User modelの管理画面上でviewの出し分けを実装することにします。
サンプルコードは下記です。
ActiveAdmin.register User do
actions :index, :show, :update, :edit
# ページング
config.per_page = 20
# 検索条件
filter :id
filter :user_id
filter :display_name
filter :email
# ファーストビューのエレメント
index do
column :id
column :user_id
column :display_name
column :mail_address
actions
end
# 詳細ページ
show do
attributes_table do
row :id
row :user_id
row :display_name
row :mail_address
row :is_banned
row :created_at
row :updated_at
end
end
# 編集項目
form do |f|
inputs do
input :id, input_html: { disabled: true } # これは編集できなくするオプションです
input :user_id,
input :display_name
input :mail_address
input :is_banned
end
actions
end
permit_params :user_id, :display_name, :mail_address, :is_banned
end
#viewの出し分け
いつものようにこんな感じで書きたくなるのですが、エラーします。。。
どうやら少し違う書き方をしないといけないようです。
ActiveAdmin.register User do
if current_user.role == :admin
filter :id
filter :display_name
filter :email
end
...
...
=> # app/admin/users.rb:2:in `block in <top (required)>': undefined local variable or method `current_user' for #<ActiveAdmin::ResourceDSL:0x00007feb5a3aea10> (NameError)
まずは検索条件のエレメントを、権限によって出し分けたいと思います。
administrator権限を持ってるユーザーだけが、emailによる絞りこみをできるようにした場合、以下のような書き方になります。
# 検索条件
filter :id
filter :user_id
filter :display_name
filter :email, if: proc { current_user.role == 'administrator' } # or { current_user.administrator? }
次ですが、index, show, edit(formの部分です)で使用するviewの切り替えは共通してます。
下記だとadministrator権限を持つユーザーでないと、showアクションのページに来ても何も表示しないことになっています。
show do
current_user.role == 'administrator'
attributes_table do
row :id
row :user_id
row :display_name
row :mail_address
row :is_banned
row :created_at
row :updated_at
end
end
end
ストロングパラメータもこんな感じで分けることができます。
permit_params do
if current_user.role == 'administrator'
params = [ :user_id, :display_name, :mail_address, :is_banned]
end
end
#まとめ
active adminのgithubリポジトリで質問したところ、今はこのような書き方にしか対応していないとの回答が帰ってきたので、if文が増えてしまって嫌なのですが、このような書き方になりました。
ブロック内でしかcurrent_userメソッドを使えないなんてほんと不便だし、自分で作りたいと強く思いましたが、短時間で管理画面作れるメリットはやっぱりデカイのでactive admin はしばらく使うと思います。
個人的には、サービスリリース時はactive adminくらいの管理画面を使って、サービスが大きくなって管理画面でいろんなことやりたい。となったら自作するのがいいと思いました。