LoginSignup
47
39

More than 3 years have passed since last update.

ActiveAdmin リソースの扱い

Last updated at Posted at 2016-08-26

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

お勧め記事

Active Admin 徹底解説 - Qiita

47
39
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
47
39