LoginSignup
0
0

ActiveAdminのカスタマイズ集 - 実用的で頻出な記法をコードサンプルにまとめてみた

Last updated at Posted at 2024-04-29

はじめに

ActiveAdminの使用を続ける中でカスタマイズ時に頻繁に使用する記法が見えてきたので、それらを詰め込んだコードサンプルを掲載します。

コードサンプルの特徴

  • ActiveAdminで app/admin/... に配置する1ファイルとして作成した
  • 私がよく書く記法を詰め込み、TIPSとしても読めそうな内容にした
  • テンプレートファイルにも流用できる構成を目指した
  • なるべく公式ドキュメントに沿ったが、一部に公式外の記法も混ぜた

想定する読者

  • ActiveAdminを使ったことがある人
    • インストール方法については記載しません
  • ActiveAdminの便利な記法やカスタマイズ方法を探している人

バージョン情報

記事公開時点の最新バージョンを使用します。

  • Ruby: 3.3.1
  • Ruby on Rails: 7.1.3
  • ActiveAdmin: 3.2.0

サンプルのテーブル構成

今回は図の中央にある company_users の管理画面を作成します。
has_many / belongs_toの両方を持っている点が特徴です。

ER図.png

class CompanyUser
  belongs_to :company
  has_many :roles
  # 自動で提案されるRansack用のメソッドは省略
end

サンプルファイル

# app/admin/company_users.rb
ActiveAdmin.register CompanyUser do
  # 1. ヘッダーメニューの並び順
  menu priority: 21

  # 2. 使用可能なアクション一覧
  actions :all, except: [:destroy]

  # 3. 編集可能なカラム名
  permit_params :company_id, :name, :active

  controller do
    # 4. DBからレコードを取得する際の処理を追加
    def scoped_collection
      super.includes(:company)
    end
  end

  # 5. フィルターをRansackの記法でカスタム
  filter :name
  filter :active
  filter :updated_at
  filter :company_id, as: :select, collection: -> { Company.all }
  filter :company_name_cont, label: '会社名 (部分一致)'

  # 6-1. 一覧表示の内容をカスタム
  index do
    selectable_column
    column :id
    column :company_id do |record|
      a href: admin_company_path(record.company) do
        "#{record.company.name}(#{record.company.code})"
      end
    end
    column :name
    column :active
    actions
  end

  # 6-2. 詳細表示の内容をカスタム
  show do
    attributes_table do
      row :id
      row :company_id do |record|
        a href: admin_company_path(record.company) do
          "#{record.company.name}(#{record.company.code})"
        end
      end
      row :name
      row :active
      row :created_at
      row :updated_at
    end
  end

  # 6-3. 編集フォームの内容をカスタム
  form do |f|
    semantic_errors(*object.errors.attribute_names)

    inputs do
      input :company_id, as: :select, collection: Company.all, include_blank: '未選択'
      input :name
      input :active
    end

    actions
  end
end

動作確認のために作成したリポジトリ

解説

1. ヘッダーメニューの並び順

menu priority: 21

公式ドキュメント Customize the Menu

menuを省略した場合の並び順は辞書順(アルファベット順)です。メニューには求めている並び順があると思いますので必ず設定した方がいいと思います。

「CompaniesとCompanyUsersの間にメニューを追加したい」というケースは結構ありますので、連番(1→2→3)にせず、飛び番(11→21→31)のように設定しておいて間に挿入できるようにしておくのが好みです。

ヘッダーメニューの設定例

2. 使用可能なアクション一覧

actions :all, except: [:update, :destroy]

公式ドキュメント Disabling Actions on a Resource

使用可能なアクションを変更する方法は「許可したいアクションを列挙(=ホワイトリスト方式)」と「許可したくないアクションを列挙(=ブラックリスト方式)」の2種類が用意されています。
公式ドキュメントには後者(ブラックリスト)しか見つけられませんでしたが、前者(ホワイトリスト)も動作しました。

# 設定可能な値
[:index, :new, :create, :edit, :update, :destroy]

# 閲覧のみ可能にする (ホワイトリスト方式の例)
actions :index, :show

# 削除を不可にする (ブラックリスト方式の例)
actions :all, except: [:destroy]

無効にしたアクションはリンクも自動で消えてくれるので結構便利です。

3. 編集可能なカラム名

permit_params :company_id, :name, :active

公式ドキュメント Setting up Strong Parameters

StrongParameter (変更してよいパラメータを制御するためのRailsが提供している機能) の設定です。これを設定しないとレコードを作成・更新することができなくなるので必ず設定します。

4. DBからレコードを取得する際の処理を追加

controller do
  def scoped_collection
    super.includes(:organization)
  end
end

公式ドキュメント Customizing resource retrieval

N+1問題の対策やwhere句の追加で活躍する書き方です。
以下にさらに複雑なサンプルを記載します。

controller do
  def scoped_collection
    records = super

    # active=trueのレコードだけを取得する。
    records = records.where(active: true)

    # N+1問題も対策する。
    records = records.includes(:company)

    # show画面の場合にのみrolesもN+1問題を対策する。
    if action_name == 'show'
      records = records.includes(:roles)
    end

    # 戻り値を設定する (忘れがちなので注意)
    records
  end
end

5. フィルターをRansackの記法でカスタム

filter :name
filter :active
filter :updated_at
filter :company_id, as: :select, collection: -> { Company.all }
filter :company_name_cont, label: '会社名 (部分一致)'

公式ドキュメント Index Filters

一覧画面の右側のフィルターをカスタマイズするための記法です。
基本的にはfilter :カラム名のように書くことが多いですが、セレクトやラジオを使ったり、関連レコードを条件に指定したりする方法も用意されています。

セレクトやラジオを使用する場合は collection -> { Company.all } のようにモデル一覧を渡すか、collection: -> { Company.all.map { |company| [company.name, company.id] } }のように[表示名, id]の配列を設定してください。

関連レコードを条件に指定する場合はRansackのドキュメントを読むと理解が深まると思います。

フィルターのスクリーンショット

6-1. 一覧表示の内容をカスタム

index do
  selectable_column
  column :id
  column :company_id do |record|
    a href: admin_company_path(record.company) do
      "#{record.company.name}(#{record.company.code})"
    end
  end
  column :name
  column :active
  actions
end

公式ドキュメント Customizing the Index Page

index do~end を省略した場合、一覧画面には全カラムが表示されます。
表示内容をカスタマイズしたり、表示するカラムを絞ったりする場合にこれを記述します。

便利と思っている記法はcompany_idのところです。今回のサンプルでは会社名+会社コードを表示し、さらにリンクにしてみました。

一覧表示の解説

6-2. 詳細表示の内容をカスタム

show do
  attributes_table do
    row :id
    row :company_id do |record|
      a href: admin_company_path(record.company) do
        "#{record.company.name}(#{record.company.code})"
      end
    end
    row :name
    row :active
    row :created_at
    row :updated_at
  end
end

公式ドキュメント Customize the Show Page
やっていることは一覧画面と同じです。

詳細画面の解説

サンプルには載せませんでしたが、panelやsidebarを活用することでたくさんの情報を体系的に表示することも可能です。

6-3. 編集フォームの内容をカスタム

form do |f|
  semantic_errors(*object.errors.attribute_names)

  inputs do
    input :company_id, as: :select, collection: Company.all, include_blank: '未選択'
    input :name
    input :active
  end

  actions
end

公式ドキュメント Forms

semantic_errors以外はこれまでに紹介した機能と概ね同じ記入です。
company_idのcollectionは5. フィルターをRansackの記法でカスタムを参照してください。

semantic_errors(*object.errors.attribute_names)はバリデーションエラーが画面に表示されないケースの対策です。公式ドキュメントに書かれていませんが、便利なのでこれを毎回書くようにしています。
「保存ボタンを押したのに画面が動かない (=保存に失敗したのにエラーメッセージが表示されないため、画面が動かないように見える)」が発生することがありました。関連レコードやフォームから変更できないカラムでバリデーションエラーが発生した場合にこれが発生します。個別に対応するのが正しいとは思いますが、とりあえずこの記法で全エラーを表示させておけば問題ないケースが多いため、いつもこれを記述するようにしています。
ちなみにsemantic_errorsのデフォルトの動作は:baseのみのバリデーションエラーを表示することです。
Qiita参考記事
GitHub Issue

スクリーンショット 2024-04-29 232140.png

おわりに

Ruby on Railsで「最速でデータを閲覧・変更できる管理画面が欲しい」と思った際、最初に思い浮かぶ候補はActiveAdminだと思います。
ActiveAdminに対しては「カスタマイズ性が悪い」とネガティブな意見を聞くこともあります。そんな時に対応策としてこの記事が活用できたらと考えて作成してみました。

実装速度に魅了されている私はメリット・デメリットを捉えながら今後もActiveAdminの使用を続けていくことになりそうです。
v4に向けた動き(v4.0.0.beta1のリリースノート)もあるようですし、今後の動向も楽しみですね。

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