ActiveAdmin リソースの扱い
【これは http://activeadmin.info/docs/2-resource-customization.html を翻訳したものです。】
リソースの作成
リソースは基本的に rails g active_admin:resource Post
といったコマンドで作成します。これは app/admin/post.rb
といった以下のような空のファイルを生成します。
ActiveAdmin.register Post do
# everything happens here :D
end
Strong parameters の設定
Rails 4 では attr_accessible
の代わりに Strong Parameters が導入されました。これはホワイトリスト化されたアトリビュートをモデルからコントローラへ渡します。
どのパラメータが変化するかを定義する permit_params
メソッドを用います。
ActiveAdmin.register Post do
permit_params :title, :content, :publisher_id
end
HABTM アソシエーションや単一の配列アトリビュートといった、複数の値を持つフォーム・フィールドからパラメータを送るには、空の配列を指定します。
ActiveAdmin.register Post do
permit_params :title, :content, :publisher_id, roles: []
end
同一フォームのネストしたアソシエーションもひとつの配列を必要としますが、アトリビュートを指定せねばなりません。
ActiveAdmin.register Post do
permit_params :title, :content, :publisher_id,
tags_attributes: [:id, :name, :description, :_destroy]
end
# 「accepts_nested_attributes_for」が必要なことに注意
class Post < ActiveRecord::Base
accepts_nested_attributes_for :tags, allow_destroy: true
end
アトリビュートを動的に指定するには、ブロックを指定します。
ActiveAdmin.register Post do
permit_params do
params = [:title, :content, :publisher_id]
params.push :author_id if current_user.admin?
params
end
end
permit_params
を呼ぶと、 permitted_params
というメソッドが生成されます。このメソッドを用いて create
または update
アクションをオーバーライドします。
ActiveAdmin.register Post do
controller do
def create
# 良い例
@post = Post.new(permitted_params[:post])
# 悪い例
@post = Post.new(params[:post])
if @post.save
# ...
end
end
end
end
リソースに対するアクションを無効にする
デフォルトではすべての CRUD アクションが有効です。これらは無効にできます。
ActiveAdmin.register Post do
actions :all, except: [:update, :destroy]
end
リソースの名前を変える
デフォルトでは、インタフェース中のリソースに対するすべてのリファレンス (メニュー, routes, ボタンなど) は、クラスの名前として用いられます。リソースの名前を変えるには :as
オプションを用います。
ActiveAdmin.register Post, as: "Article"
上記のリソースには /admin/articles
でアクセスできます。
名前空間のカスタマイズ
デフォルトの admin
名前空間は、以下のように変更できます。
# /today/posts でアクセス
ActiveAdmin.register Post, namespace: :today
# /posts でアクセス
ActiveAdmin.register Post, namespace: false
メニューのカスタマイズ
デフォルトでは、グローバル・ナビゲーションにリソースが表示されます。グローバル・ナビゲーションにリソースが表示されないようにするには以下のようにします。
ActiveAdmin.register Post do
menu false
end
menu
メソッドは以下のオプションをハッシュとして受け取ります。
-
:label
- メニューに表示する文字列または proc label。proc を指定すると、メニューがレンダリングされるたびにその proc が呼ばれます。 -
:parent
- 親がそのメニューを用いるとき使用する文字列ID (またはラベル) -
:if
- そのメニューを表示するかどうかを決定するブロックまたはメソッドのシンボル -
:priority
- プライオリティ値。デフォルトは10。
ラベル
メニューのラベルを変更するには、以下のようにします。
ActiveAdmin.register Post do
menu label: "My Posts"
end
より動的に変更するには、proc を指定します。
ActiveAdmin.register Post do
menu label: proc{ I18n.t "mypost" }
end
メニュー・プライオリティ
メニューの要素は、まずそのプライオリティ数に従って並べられ、次にアルファベット順に並べられます。なのですべてのメニューのプライオリティがデフォルトの10である場合は、常にアルファベット順になります。
これをカスタマイズするには以下のようにします。
ActiveAdmin.register Post do
menu priority: 1 # 左端になります
end
メニュー要素の表示/非表示の制御
:if
オプションでメニューを表示したりしなかったりすることができます。
ActiveAdmin.register Post do
menu if: proc{ current_user.can_edit_posts? }
end
ドロップダウンメニュー
多くの場合、大きなアプリケーションではシングル・レベルのナビゲーションは不十分です。そのような場合、メニュー要素をグループ化して親メニューの下にすることができます。
ActiveAdmin.register Post do
menu parent: "Blog"
end
「Blog」というメニュー要素を作成する必要がない点に注意して下さい。動的に作成されます。
親メニュー要素のカスタマイズ
普通のメニュー要素に使えるオプションは、すべて親メニュー要素に使えます。複雑な親メニュー要素を使う場合には、Active Admin 初期化ファイルで設定してください。
# config/initializers/active_admin.rb
config.namespace :admin do |admin|
admin.build_menu do |menu|
menu.add label: 'Blog', priority: 0
end
end
# app/admin/post.rb
ActiveAdmin.register Post do
menu parent: 'Blog'
end
動的親メニュー要素
上記がうまく動いたとしても、親メニュー要素のラベルを動的に変更するにはどうすればよいでしょうか?その場合は親メニュー要素の :id
を参照するようにしてください。
# config/initializers/active_admin.rb
config.namespace :admin do |admin|
admin.build_menu do |menu|
menu.add id: 'blog', label: proc{"Something dynamic"}, priority: 0
end
end
# app/admin/post.rb
ActiveAdmin.register Post do
menu parent: 'blog'
end
カスタム・メニュー要素の追加
メニュー・ラベルをもっとカスタマイズしたい場合があります。この場合は、Active Admin 初期化ファイルの名前空間でメニューをカスタマイズできます。
# config/initializers/active_admin.rb
config.namespace :admin do |admin|
admin.build_menu do |menu|
menu.add label: "The Application", url: "/", priority: 0
menu.add label: "Sites" do |sites|
sites.add label: "Google", url: "http://google.com", html_options: { target: :blank }
sites.add label: "Facebook", url: "http://facebook.com"
sites.add label: "Github", url: "http://github.com"
end
end
end
上記は、アプリケーションが開始した後で、リソースがロードされる前に登録されます。
アクセス権限
管理者に異なるアクセスレベルがある場合、アクセス権を持っているかどうか調べる必要があるでしょう。ユーザ・モデルに has_many リレーションシップがあると仮定した場合、以下のように簡単に制御できます。
ActiveAdmin.register Post do
scope_to :current_user # アクセスできるポストを `current_user.posts` に制限する
# アソシエーションがデフォルト名でない場合
scope_to :current_user, association_method: :blog_posts
# ブロックを渡すこともできます
scope_to do
User.most_popular_posts
end
end
アクセス権を条件付きにすることもできます。
ActiveAdmin.register Post do
scope_to :current_user, if: proc{ current_user.limited_access? }
scope_to :current_user, unless: proc{ current_user.admin? }
end
Eager Loading
eager loading を使って N+1 問題を解決すると、一般的にページのパフォーマンスが良くなります。
ActiveAdmin.register Post do
includes :author, :categories
end
リソース検索のカスタマイズ
ActiveAdminのコントローラは継承リソースで実装されているので、そのすべての機能を使うことができます。
コレクションのプロパティをカスタマイズする場合は、scoped_collection
メソッドをオーバーライドしてください。
ActiveAdmin.register Post do
controller do
def scoped_collection
end_of_association_chain.where(visibility: true)
end
end
end
レコード検索コードを完全に書き換えなければならない場合 (例: モデル内で to_param
をカスタム実装している)、コントローラの resource
メソッドをオーバーライドしてください。
ActiveAdmin.register Post do
controller do
def find_resource
scoped_collection.where(id: params[:id]).first!
end
end
end
CanCan のような権限管理ライブラリを使っている場合、以下のように書かないよう注意してください。このようにすると、権限ルールが無効になってしまいます。
ActiveAdmin.register Post do
controller do
def find_resource
Post.where(id: params[:id]).first!
end
end
end
belongs_to
リレーションシップに対するリソースを、アクセス制御したいことはよくあります。例えば、プロジェクトはマイルストーンとチケットを持っています。あるリソースを他のリソースに対してネストするには、 belongs_to
メソッドを使います。
ActiveAdmin.register Project
ActiveAdmin.register Ticket do
belongs_to :project
end
/admin/projects/1/tickets
にアクセスすることでプロジェクトには普通にアクセスでき、プロジェクトは id が 1 のものがひとつだけあると仮定します。Active Admin は「チケット」をナビゲーションに追加しないのですが、それはプロジェクトの id がないと routes を決定できないからです。
リソースへのリンクを作成するには、サイドバーを使います。(サイドバーはとても使い勝手の良いユーザ・インタフェースです。)
ActiveAdmin.register Project do
sidebar "Project Details", only: [:show, :edit] do
ul do
li link_to "Tickets", admin_project_tickets_path(project)
li link_to "Milestones", admin_project_milestones_path(project)
end
end
end
ActiveAdmin.register Ticket do
belongs_to :project
end
ActiveAdmin.register Milestone do
belongs_to :project
end
ときおり (プロジェクトのように)、たくさんのサブ・リソースがあると、プロジェクトの「情報」をグローバル・ナビゲーションで切り替えたくなることが実際あります。これに対応するために、Active Admin は belongs_to
リソースを別のメニューに分けています。
ActiveAdmin.register Ticket do
belongs_to :project
navigation_menu :project
end
ActiveAdmin.register Milestone do
belongs_to :project
navigation_menu :project
end
これで、「チケット」セクションにナビゲートする際、グローバル・ナビゲーションには「チケット」と「マイルストーン」だけが表示されるようになります。belongs_to でないリソースに戻ると、グローバル・ナビゲーションもデフォルト・メニューに戻ります。
多分ユーザ権限の関連で、異なるメニューを実行時に動的に決定したい場合があるでしょう。以下のようにします。
ActiveAdmin.register Ticket do
belongs_to :project
navigation_menu do
authorized?(:manage, SomeResource) ? :project : :restricted_menu
end
end