Railsでは、Active Adminを使うことで管理者画面を容易に作ることができます。
Active Admin | The administration framework for Ruby on Rails
そんな中、Active AdminでModelの作成・更新・削除を行うと同時に、Modelとは関係ないAPIを呼ぶ処理を追加したくなったため、調べた時のメモを残します。
目次
環境
- Rails 6.1.4
- Active Admin 2.9.0
- Devise 4.8.0
- Active Adminの管理ページをログイン必須にするために使用
ベースとなるActive Adminアプリの作成
Active Adminのセットアップ
まずは、追加する前のActive Adminアプリを作成します。
今回はRails6.1系のため、assets generatorにWebpackerを使ったアプリを作成します。
rails new します。
% rails new rails_with_active_admin_app
Gemfileにactive adminとdeviseを追加して、 bundle install
します。
gem 'activeadmin' gem 'devise'
このまま起動してもWebpackerまわりでエラーになるため、Webpackerのセットアップを行います。
% bin/rails webpacker:install create config/webpacker.yml Copying webpack core config create config/webpack create config/webpack/development.js create config/webpack/environment.js create config/webpack/production.js create config/webpack/test.js Copying postcss.config.js to app root directory create postcss.config.js Copying babel.config.js to app root directory create babel.config.js Copying .browserslistrc to app root directory create .browserslistrc The JavaScript app source directory already exists apply path/to/rails_with_active_admin_app/vendor/bundle/ruby/3.0.0/gems/webpacker-5.4.0/lib/install/binstubs.rb Copying binstubs exist bin create bin/webpack create bin/webpack-dev-server append .gitignore Installing all JavaScript dependencies [5.4.0] run yarn add @rails/webpacker@5.4.0 from "." ... ✨ Done in 6.49s. Webpacker successfully installed 🎉 🍰
Active Adminの初期化を行います。
Webpackerはオプトインのため、 use_webpacker
オプションを追加してWebpackerを使うようにします。
webpacker | Installation | Active Admin | The administration framework for Ruby on Rails
% bin/rails g active_admin:install --use_webpacker Running via Spring preloader in process 11165 create config/initializers/active_admin.rb create app/admin create app/admin/dashboard.rb route ActiveAdmin.routes(self) generate active_admin:webpacker rails generate active_admin:webpacker Running via Spring preloader in process 11173 create app/javascript/packs/active_admin.js create app/javascript/stylesheets/active_admin.scss create app/javascript/packs/active_admin/print.scss create config/webpack/plugins/jquery.js insert config/webpack/environment.js insert config/webpack/environment.js run yarn add @activeadmin/activeadmin from "." yarn add v1.22.10 [1/4] 🔍 Resolving packages... [2/4] 🚚 Fetching packages... [3/4] 🔗 Linking dependencies... [4/4] 🔨 Building fresh packages... success Saved lockfile. success Saved 4 new dependencies. info Direct dependencies └─ @activeadmin/activeadmin@2.9.0 info All dependencies ├─ @activeadmin/activeadmin@2.9.0 ├─ jquery-ui@1.12.1 ├─ jquery-ujs@1.2.3 └─ jquery@3.6.0 ✨ Done in 6.09s. create db/migrate/20210715221110_create_active_admin_comments.rb
ちなみに、今回はDeviseを使っているため関係ないですが、Deviseを使っていない場合は --skip-users
オプションを追加してActiveAdminを初期化します。
bin/rails g active_admin:install --use_webpacker --skip-users
続いてDBまわりのセットアップを行います。
Setting up Active Admin | Active Admin | The administration framework for Ruby on Rails
% bin/rails db:migrate % bin/rails db:seed
ここまでで準備ができたため、Railsを起動します。
% bin/rails s
この状態で http://localhost:3000/admin にアクセスし、以下の情報でログインできればOKです。
- User: admin@example.com
- Password: password
Modelを作成
今回は以下の項目を持つ Fruit
モデルを用意します。
論理名 | 物理名 | 型 | 制約 |
---|---|---|---|
名前 | name | string | unique |
色 | color | string | - |
販売開始日時 | start_of_sales | datetime | - |
Model Fruit
を作成します。
% bin/rails g model Fruit name:string:unique color:string start_of_sales:datetime
マイグレーションします。
% bin/rails db:migrate
Active Adminで管理できるようにする
Modelができたため、次はActive Adminで管理できるようにします。
app/admin/fruit.rb
を作成します。
今回、Active Adminの画面では
- name
- color
のみ編集可能とするため、 permit_params
を使って指定します。
Setting up Strong Parameters | Working with Resources | Active Admin | The administration framework for Ruby on Rails
ActiveAdmin.register Fruit do permit_params :name, :color end
これで、Controller Admin::Fruit
が生成されます。
Content rendering API · activeadmin/activeadmin Wiki
動作確認
http://localhost:3000/admin/fruits/new
にアクセスします。
color
は color pickerになっています。もし color pickerを使いたくない場合は、以下のようにしてカスタマイズできそうです。
ruby on rails - ActiveAdmin: how to have a text field instead a color picker to input a color? - Stack Overflow
また、permit_paramsで指定していない start_of_sales
も表示されています。
入力して作成します。
作成した後です。 start_of_sales
は入力したはずですが、登録されていません。
Controllerのcreate/update/destroyをオーバーライドする
本題になります。APIを呼ぶ処理を追加するために、Controllerのメソッドをオーバーライドしていきます。
まず、上で見たController Admin::Fruit
の親の定義を見たところ、以下にありました。
https://github.com/activeadmin/activeadmin/blob/v2.9.0/lib/active_admin/base_controller.rb#L7
module ActiveAdmin # BaseController for ActiveAdmin. # It implements ActiveAdmin controllers core features. class BaseController < ::InheritedResources::Base
さらに、 InheritedResources::Base
は、別のgem inherited_resources
にて定義してあります。
https://github.com/activeadmin/inherited_resources/blob/v1.13.0/app/controllers/inherited_resources/base.rb#L11
さらにこの中でincludeされているのが InheritedResources:: Actions
です。
https://github.com/activeadmin/inherited_resources/blob/v1.13.0/lib/inherited_resources/actions.rb
そのため、 InheritedResources:: Actions
の各メソッドをオーバーライドすることで、APIを呼ぶ処理を追加できそうです。
オーバーライドは controller
メソッドのブロックに定義します。
- Modifying the Controller | Custom Controller Actions | Active Admin | The administration framework for Ruby on Rails
- ruby on rails - Can I override just part of an ActiveAdmin controller action using
super
+ custom redirect? - Stack Overflow
今回は inherited_resources
でのオーバーライド方法にならい、 super do
な形にしてみます。
Overwriting actions | activeadmin/inherited_resources
ActiveAdmin.register Fruit do permit_params :name, :color # コントローラのcreate/update/destroyをオーバーライド controller do def create super do |format| call_api(:create) end end def update super do |format| call_api(:update) end end def destroy super do |format| call_api(:destroy) end end private def call_api(method) # 外部APIを呼んだつもり # (今回はログに出力する) logger.info("======> called api by #{method}") end end end
動作確認
Fruitに対して作成・更新・削除を行ったところ、以下のようなログが出力されていました。
メソッドをオーバーライドできました。
# 作成 Started POST "/admin/fruits" for 127.0.0.1 at 2021-07-17 21:34:04 +0900 ... Fruit Create (1.3ms) INSERT INTO "fruits" ("name", "color", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "みかん"], ["color", "#f2ad18"], ["created_at", "2021-07-17 12:34:04.759054"], ["updated_at", "2021-07-17 12:34:04.759054"]] ↳ app/admin/fruit.rb:7:in `create' TRANSACTION (1.3ms) commit transaction ↳ app/admin/fruit.rb:7:in `create' ======> called api by create # 更新 Started PATCH "/admin/fruits/9" for 127.0.0.1 at 2021-07-17 21:34:13 +0900 ... Fruit Update (0.5ms) UPDATE "fruits" SET "name" = ?, "updated_at" = ? WHERE "fruits"."id" = ? [["name", "夏みかん"], ["updated_at", "2021-07-17 12:34:13.249457"], ["id", 9]] ↳ app/admin/fruit.rb:13:in `update' TRANSACTION (0.9ms) commit transaction ↳ app/admin/fruit.rb:13:in `update' ======> called api by update # 削除 Started DELETE "/admin/fruits/9" for 127.0.0.1 at 2021-07-17 21:34:16 +0900 Processing by Admin::FruitsController#destroy as HTML ... ↳ app/admin/fruit.rb:19:in `destroy' ======> called api by destroy Redirected to http://localhost:3000/admin/fruits
ソースコード
Githubに上げました。
https://github.com/thinkAmi-sandbox/rails_with_active_admin_app
関係するプルリクはこちらです。
https://github.com/thinkAmi-sandbox/rails_with_active_admin_app/pull/1