4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ActiveAdmin のメニュー設定をすごく便利にする ActiveAdmin::MenuTree のご紹介

Last updated at Posted at 2022-02-20

ActiveAdminのメニュー設定を便利にする ActiveAdmin::MenuTree というgemを作ったのでご紹介します。

ActiveAdminとは

ActiveAdminとは、Railsで管理画面をさくっと作れるフレームワークですね。とても便利です。
ここではActiveAdmin自体についてはある程度知っている(使ったことがある)前提として話を進めます。

なお、ActiveAdmin v2.10.0 時点の情報になります。

ActiveAdminのメニューはカスタマイズできる

さて、これをお読みいただいているみなさまは、ActiveAdminのメニューをカスタマイズする方法はご存知でしょうか。

ActiveAdminでは、リソースを作ればデフォルトで何もしなくてもメニューに表示されるので、小規模プロジェクトだと気にならずにそのまま使っている場合も多いかもしれません。

しかし、少し規模が大きくなってリソースの数が増えてくると、どこに何があるかわかりづらくなりますよね。

何もしないとこんな感じになってしまう

dummy before
たくさんあるとたいへん

こういうふうにカスタマイズできます

dummy after
グループ化したり、順番を入れ替えたり、好きなラベルを設定したりできます。

このように、ActiveAdminではメニューをある程度カスタマイズする方法が提供されています。

ActiveAdmin公式のメニューカスタマイズ方法

まずはActiveAdminでできるメニューカスタマイズの方法をご紹介します。

公式ドキュメントに書いてある内容をベースに紹介します。

ActiveAdminの各リソースでmenuメソッドを使う

まず、ActiveAdminの各リソースでmenuメソッドに引数を渡すのが基本的な設定方法になります。

たとえば、menuメソッドにfalseを渡すことで特定のリソースでメニューを無効にでき、そのリソースがメニューに表示されなくなります。
もちろんページ自体はなくならないので、パスを開けばアクセスできます。

# app/admin/post.rb
ActiveAdmin.register Post do
  menu false
end

menuメソッドで使える4つのオプション

menuメソッドでは以下の4つのオプションによってメニューをカスタマイズできます。

  • :label - 文字列かprocでメニューに表示するラベルを設定できる
  • :parent - 文字列IDかラベルで親メニューを指定できる(ネストさせることができる)
  • :if - ブロックかメソッドのシンボルでメニューを表示するかどうか制御できる
  • :priority - 数値で優先度を設定できる(デフォルトは10)

ここではpriorityparentを中心に紹介します。

Menu Priority

  • prioriyでメニューの優先度を設定できます
  • 数値が小さいほど左側に表示されます
  • 数値が同じ場合は名前順になります
  • デフォルトは10
ActiveAdmin.register Post do
  menu priority: 1
end

Drop Down Menus

  • parentで親メニューを設定することで、メニューをグループ化できます
  • 指定したparent(以下の例のBlog)は、存在しなければ自動で作られます
ActiveAdmin.register Post do
  menu parent: "Blog"
end
  • 配列で指定するとさらにネストできます
ActiveAdmin.register Post do
  menu parent: ["Admin", "Blog"]
end

Customizing Parent Menu Items

  • 親メニューをカスタマイズする場合はイニシャライザで設定します
  • 通常のmenuと同じオプションが使えます
  • 子メニューからはparentで同じラベル名(またはid)を指定することで識別します
# 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

Dynamic Parent Menu Items

  • 親メニューのラベルを動的にしたい場合は、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

ここが不便だよActiveAdmin

以上のように、ActiveAdminではメニューのカスタマイズが可能なのですが、主に以下の2点が少し不便だと思っています。

  • priority での順序管理
    • 一度設定したメニューの順番を変更する場合、各リソースのpriorityを一つずつ変更する必要がある
    • adminリソースのファイルはメニューの順番に並んでるわけではないので、どれがどれだかわからなくなる
  • parent での階層関係の管理
    • 親メニューをカスタマイズするにはイニシャライザで設定する必要がある

ひとことで言うと、設定が各リソースファイルに分散していて変更が面倒です。
特に親メニューと通常のメニューが混在して順序を管理したい場合などに顕著になると思います。

そこで ActiveAdmin::MenuTree

ActiveAdmin::MenuTree を使えば、前述の不便な点を解消して、メニューをyamlで直感的に管理できます。

ActiveAdmin::MenuTree の使い方

ここからようやく ActiveAdmin::MenuTree の使い方の紹介になります。

インストール

インストールは普通にgemを追加するだけ。

# Gemfile
gem 'activeadmin-menu_tree'
# インストール
$ bundle install

使い方はたった2ステップ!

かんたんです。

1. menu_tree の設定

yamlで設定を書いて、イニシャライザで読み込む。

# config/activeadmin-menu_tree.yml or anywhere you like
activeadmin:
  menu_tree:
    - id: Dashboard
    - label: Admin
      children:
        - id: AdminUser
          label: Admin Users
        - id: Comment
          label: Admin Comments
# config/initializers/activeadmin-menu_tree.rb
ActiveAdmin::MenuTree.setup do |config|
  config.menu_tree = YAML.load_file(Rails.root.join("config/activeadmin-menu_tree.yml"))["activeadmin"]["menu_tree"]
end
2. ActiveAdminの各リソースで menu_tree を呼び出す

通常はmenuメソッドで設定しているところをmenu_treeに変更

# app/admin/admin_users.rb
ActiveAdmin.register AdminUser do
  menu_tree
  # ...
end

# app/admin/dashboard.rb
ActiveAdmin.register_page "Dashboard" do
  menu_tree label: proc { I18n.t("active_admin.dashboard") }
  # ...
end
  • priority/parentは設定不要になるので消してOK
  • menuメソッドと同様のオプションを渡せるので、labelifはそのまま動的に設定可能
これでRailsを起動すればメニューがいい感じに設定されています

sample

その他の設定読み込み方法

また、ActiveAdmin::MenuTreeでは、yamlを使わずにシンプルにHashで設定することもできます。
procを使った動的な指定をしたい場合は、こちらを使うのがよいかもしれません。

ActiveAdmin::MenuTree.setup do |config|
  config.menu_tree = [
    { id: "Dashboard", label: proc { I18n.t("active_admin.dashboard") } },
    {
      label: "Foo",
      if: proc { "Something dynamic" }
      children: [
        { id: "Bar" },
        { id: "Baz" }
      ]
    }
  ]
end

Config gemを使っている場合は、to_hashメソッドでHashにすることで使えます。

ActiveAdmin::MenuTree.setup do |config|
  config.menu_tree = Settings.activeadmin.menu_tree.map(&:to_hash)
end
# config/settings.yml
activeadmin:
  menu_tree:
    # ...

Global gemなどでも同様にHashに変換すれば使えると思います。

フル設定例

yamlで使える全設定例は以下のような感じです。

activeadmin:
  menu_tree:
    # Specify the resource with `id`.
    - id: Dashboard
    - id: Product
    # Specify a menu label with `label`.
    - label: User Info
      # Specify child elements with `children`.
      children:
        - id: User
        - id: Profile
    - label: Admin
      children:
        - id: AdminUser
          label: Admin Users
        # Comment resource will be handled specially.
        - id: Comment
          label: Admin Comments
    - label: Others
      children:
        - id: Foo
        - id: Bar
    - label: Example Site
      # You can pass the other options available for `menu` DSL, like `url`, `html_options`.
      url: 'https://example.com'
      html_options:
        target: blank
    # Nesting of children is also available.
    - label: Lorem
      children:
        - label: ipsum
          children:
            - label: dolor
              children:
                - label: sit
                  children:
                    - label: amet
                      url: 'https://wikipedia.org/wiki/Lorem_ipsum'
                      html_options:
                        target: blank
  • id - リソースIDを指定します(通常はモデル名)
  • label - ラベルを指定します
  • children - 子要素を配列で指定します
  • Commentリソースは通常リソースファイルがないですが、特別に処理されます
  • url, html_optionsなど、menuメソッドで使えるオプションはそのまま渡せます
    • ※yamlなのでrubyの動的な指定はできません
screenshot

こんな感じで、 ActiveAdmin::MenuTree を使えば ActiveAdmin のメニューをわかりやすく設定できます。

おまけ: gemの命名規則について

gemを作ったことのある方なら知っているかと思いますが、gemの名前を決める際の指針として、RubyGems公式のガイドラインがあります。

ざっくりポイントは以下の3点です。
・複数単語をくっつける場合はアンダースコア
・階層が分かれる場合はハイフン
・大文字や他の記号は使わない

そして、 ActiveAdmin と ActiveAdmin::MenuTree の命名は以下のようになっています。

GEM NAME REQUIRE STATEMENT MAIN CLASS
activeadmin require 'activeadmin'
or require 'active_admin'
ActiveAdmin
activeadmin-menu_tree require 'activeadmin/menu_tree' ActiveAdmin::MenuTree

これを見ると、activeadminというgem名はガイドラインを守っていないことになりますね。
一応requireではactiveadminでもactive_adminでもどちらでも読み込めるようになっています。ref.

ちなみに、ActiveAdminに限らずこのガイドラインを守っていない有名gemもそれなりにありますね。
(Rails関連のactivexxx系やactionxxx系を筆頭に)

ActiveAdmin::MenuTree では、activeadminの部分は本家と同じにし、menu_treeの部分はガイドラインに従う形にしました。

今後gemを作る方の参考になれば。

おわりに

  • ActiveAdminのメニュー設定を便利にする ActiveAdmin::MenuTree というgemのご紹介でした。ぜひみなさん使ってみてください!
  • 不具合など見つけた方はissueなどで優しく教えてください
  • プルリクエストも歓迎です
4
0
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
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?