Edited at

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

More than 1 year has passed since last update.


2016/11/22 追記

この記事の内容が(さらに改善されて)gemになりました。

https://github.com/yhirano55/active_admin_menu


シチュエーション

https://github.com/activeadmin/activeadmin/blob/master/docs/2-resource-customization.md#menu-priority

上記ヘルプに(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のアプリケーションを配置しているためです。そうでない人は適宜読み替えてください。