LoginSignup
11
11

More than 5 years have passed since last update.

ActiveAdminでメニューの並び順を1箇所で管理する

Last updated at Posted at 2015-05-24

2016/11/22 追記

この記事の内容が(さらに改善されて)gemになりました。
https://github.com/yhirano55/active_admin_menu

シチュエーション

上記ヘルプに(2015/05/24時点で)あるように、ActiveAdminでページを作ってメニューの設定を行うとき、並び順を決定するための優先度は各ページに書く必要があります。
しかしこれではページが多くなってくると管理が面倒になります。

実装

config/initializers/active_admin_menus.rb
MENU_ITEMS = [
  [:item, 'Dashboard', {label: proc{ I18n.t("active_admin.dashboard") }}],
  [:item, 'Item', {}],
  [:item, 'Skill', {label: '特技検索'}],
  [:item, 'Evolution', {label: '進化検索'}],
  [:category, 'master',
    [
      ['Element', {}],
      ['BoxKind', {}],
    ]
  ],
  [:item, 'Comment', {}],
]

MENU_ITEM_EXCLUDES = %w()

def inverted_menu_items
  MENU_ITEMS.each_with_object([]).with_index do |(source_item, inverted), index|
    case source_item.first
    when :item
      _, page, args = source_item
      inverted << [page, args.merge(priority: index)]
    when :category
      _, category, children = source_item
      inverted << [category, {label: I18n.t("active_admin.menu.#{category}"), priority: index}]
      children.each_with_index do |category_item, index2|
        page, args = category_item
        inverted << [page, args.merge(parent: I18n.t("active_admin.menu.#{category}"), priority: index2)]
      end
    end
  end
end

def check_index_and_add_priority_and(name, &block)
  index = inverted_menu_items.map(&:first).index(name)
  if index
    args = inverted_menu_items[index][1]
    block.call(args)
  elsif !(MENU_ITEM_EXCLUDES.include? name)
    raise "#{name} is NOT placed into the menu"
  end
end

ActiveAdmin.application.namespace(false).build_menu do |menu|
  MENU_ITEMS.select {|i| i.first == :category}.each do |item|
    name = item[1]
    check_index_and_add_priority_and(name) do |args|
      menu.add args
    end
  end
end

class ActiveAdmin::DSL
  def allocate_to_menu
    name = config.resource_name.name
    check_index_and_add_priority_and(name) do |args|
      menu args
    end
  end
end

module MenuAllocator
  def register(*args, &block)
    super *args do
      allocate_to_menu
      self.instance_eval &block
    end
  end

  def register_page(*args, &block)
    super *args do
      allocate_to_menu
      self.instance_eval &block
    end
  end
end

module ActiveAdmin
  class Namespace
    prepend MenuAllocator
  end
end

解説

基本方針

ページの登録時の処理をフックして、各ページのコードから呼び出すmenuコマンドを、設定したメニューの並び順(priority)を含んだ形で呼びだします。

例外的な処理

注意点

  • menuコマンドは1つのページから複数回呼び出せますが、最後に呼び出したものの引数の内容だけが適用されるので、各ページの実装からmenuコマンドを呼び出すとここでの設定が反映されません。
  • namespace(false)なのは、 http://qiita.com/skuroki@github/items/fbded7846a78feb8bef1 の例2のやりかたで / 直下にActiveAdminのアプリケーションを配置しているためです。そうでない人は適宜読み替えてください。
11
11
0

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
11
11