はじめに
はじめまして。プログラミングスクール RUNTEQ を卒業したばかりの初学者、りたと申します。
卒業制作でgem Administrateを採用して管理画面を作成したのですが、いろいろとカスタマイズをしたので、何をどういじったのかの記録を残しておこうと思います。
というのも、たまにAdministrateをいじろうと思ったときに、どこをどうカスタマイズしたか、どこをいじればなにができる(できた)のかを思い出すのに時間がかかったことがあったので、未来の自分のためにも記事にしておこうと思いました。
gem Administrateの導入や基本的な使い方に関してはこの記事には載せません。
公式ドキュメントや各種技術記事等をご参照ください。
Administrateを何かしがいじることがあれば、今後も追記していきます。
注意
初学者のため、内容に誤りがある可能性があります。
間違いなどありましたら、コメント欄等でご指摘いただけますと大変助かります。
追記(2025/11/11)
記事執筆時のAdministrateのバージョンは0.20.1でした。
2025/10/30よりAdministrateのバージョン1.0.0が公開されました。
この記事の情報はバージョン0.20.1時代のものですが、1.0.0でも問題なく動いているのを確認しています。
開発環境
- WSL(Ubuntu 22.04LTS)
- Docker
- Ruby 3.3.6
- Rails 7.2
- Administrate 0.20.1
- ActiveStorage使用
ActiveStorageに対応させる&投稿を編集しても画像が消えないようにする
AdministrateはデフォルトでActiveStorage(というかファイルアップローダー)に対応していませんので、画像を表示させることが出来ません。
なので、専用のカスタムフィールドを作成するなどして画像の表示等画像管理に対応させる必要があります。
ActiveStorageを採用している場合は、gem Administrate::Field::ActiveStorageという、AdministrateをActiveStorageに対応させる専用のカスタムフィールドを追加するgemがあるので、これを使用すると簡単に画像の管理ができるようになります。
gem Administrate::Field::ActiveStorageの使い方に関しては公式ドキュメントをご参照ください。
以前投稿した記事(【Rails7】画像付きの投稿を画像のアップロードなしで編集すると、添付画像が消えてしまう)にも書きましたが、Railsはfile_fieldにmultiple: trueオプションを設定している時、画像添付済みの投稿を画像のアップロードなしで編集するともともと添付してた画像を消してしまいます。
Administrate::Fields::ActiveStorage公式ドキュメントには、専用のモジュールを作ってこの仕様を回避する、という回避策が取られていますが、もっと簡単に回避できる方法があります。
ダッシュボードで、下記のようにfile_field_optionsというオプションでinclude_hidden: falseを設定すれば、file_fieldにinclude_hidden: falseを設定できます。
...
images: Field::ActiveStorage.with_options(
index_preview_size: [80, 80],
show_preview_size: [350, 350],
file_field_options: { include_hidden: false },
destroy_url: proc do |namespace, resource, attachment|
[:images_admin_review, { attachment_id: attachment.id }]
end
),
...
このfile_field_optionsはfile_fieldに渡すオプションを設定できる項目なのですが、この項目の書き方の部分がREADMEから削除されてしまっていたので、探すのに苦労しました…。
画像削除のRemoveボタンをindexに表示させないようにする(gem Administrate::Field::ActiveStorage)
gem Administrate::Field::ActiveStorageで管理画面での画像削除機能を実装すると、index・show・editで画像のRemoveボタンが追加されます。
ですが、indexで画像を削除できるようにする必要はあんまりないので、このRemoveボタンをindexから削除します。
ありがたいことに公式のissue(Delete button #77)にやり方を載せてくれている人がいたので、このやり方でやります。
通常、Administrateだとrails generate administrate:views:index Userやrails generate administrate:field select等のコマンドで修正したいビューファイルを生成することが出来ますが、gem Administrate::Field::ActiveStorageにはこのようなコマンドがないので、手動でファイルを作成します。
GitHubを見ると、app/views/fields/active_storage/_item.html.erbというファイルをいじればよさそうです。
というわけで、app/views配下にfields/active_storage/_item.html.erbファイルを作成します。
<% if field.destroy_url.present? %>
<% destroy_url = field.destroy_url.call(namespace, field.data.record, attachment) %>
<div>
<%= link_to I18n.t("administrate.fields.active_storage.remove", default: 'Remove'),
destroy_url, method: :delete, class: 'remove-attachment-link', data: { confirm: t("administrate.actions.confirm") } %>
</div>
<hr>
<% end %>
いじる部分はここで、下記のように変更します。
<% if action_name.in?(%w(show edit)) && field.destroy_url.present? %>
<% destroy_url = field.destroy_url.call(namespace, field.data.record, attachment) %>
<div>
<%= link_to I18n.t("administrate.fields.active_storage.remove", default: 'Remove'),
destroy_url, method: :delete, class: 'remove-attachment-link', data: { confirm: t("administrate.actions.confirm") } %>
</div>
<hr>
<% end %>
action_nameはコントローラーのアクション名を取ってこれるメソッドです。
このメソッドを使ってアクションがshowかeditの時のみRemoveボタンを表示するように条件分岐を変更します。
これで、indexからRemoveボタンが消えました。
Administrateに独自のJSを適用する
AdministrateはCSSもJSもAdministrate自身のものしか使わない設定になっています。
なので、普通に(例えばStimulus等で)独自のJSファイルを作成しても、そのままでは適用出来ません。
独自のJSを適用したいときは、適用したいViewファイルに以下のコードを追加します。
<% content_for :javascript do %>
<%= javascript_include_tag "application" %>
<% end %>
これで、このコードのあるViewファイルでは独自のJSファイルが読み込めるようになります。
gem ActiveHash用のカスタムフィールドを作成する
Administrateはモデルを参考にダッシュボード等を自動生成します。
gem ActiveHashは、都道府県等のとくに変更されないデータをモデルファイルに直接記述することで、データベースにデータを保存せずに使うことができるgemです。
ActiveHashはモデルを作るのではなく、擬似モデルを作成してモデルのようにふるまわせます。
なので、AdministrateでActiveHashで作成したモデルのダッシュボード等を作らせようとすると、テーブルないよといわれます。
とはいえ、(少なくとも私の使い方では)ActiveHashのデータに管理画面で管理したいデータは特にないので、ActiveHashで作った擬似モデルと関連づいているモデルにActiveHashのデータを表示させるとか、関連づいてるモデルのデータにActiveHashのデータを設定するとかが出来ればOKです。
というわけで、ActiveHash用のカスタムフィールドを作成します。
カスタムフィールドの作成方法は公式ドキュメントの記載通りやっていきます。
rails generate administrate:field category
このコマンドでCategoryFieldというカスタムフィールド用の各種ファイルが生成されます。
まずはapp/fields/category_field.rbにカスタムロジックを追加します。
require "administrate/field/select"
class CategoryField < Administrate::Field::Select
def category_name
Category.find(data).color
end
def html_controller
"select"
end
end
ファイルを生成しただけの状態だとAdministrate::Field::Baseが継承されていますが、今回はAdministrate標準のField::Selectを流用したいのでAdministrate::Field::Selectを継承するように変更しています。
category_nameはActiveHashの擬似モデルCategoryのcolorカラムを表示する用のメソッドです。
dataにはIDしか入っておらず、dataからcolorを呼び出すことが出来なかったので、find()で探させてcolorを表示するようにしています。
html_controllerはapp/views/fields/category_field/_form.html.erbで使用されるメソッドで、Stimulusのコントローラーを呼び出すのに使っているようです。
<div class="field-unit__label">
<%= f.label field.attribute %>
</div>
<div class="field-unit__field">
<%=
f.select(
field.attribute,
options_for_select(
field.selectable_options,
field.data,
),
{include_blank: field.include_blank_option},
data: {controller: field.html_controller}
# html_controllerに"select"が入っているので、Administrateのselect_controller.jsが呼び出される。
)
%>
</div>
app/fields/category_field.rbはAdministrate標準のField::Selectの_form.html.erbをそのままコピペして使います。
app/views/fields/category_field/_index.html.erbおよびapp/views/fields/category_field/_show.html.erbは下記のように書き換えます。
<%= field.category_name %>
これで、擬似モデルCategoryのcolorカラムの内容が表示されるようになります。
最後に、ダッシュボードに以下のように書きます。
...
category_id: CategoryField.with_options(
collection: Category.all.collect { |c| [ c.color, c.id ] },
include_blank: true,
),
...
Categoryは擬似モデルで、実際のモデルはないため普通にCategoryFieldだけ定義しても、category_idに入ってるIDしか表示されません。
なので、with_optionsでオプション設定として、collectionで擬似モデルCategoryのデータを渡してやります。
CategoryFieldはField::Selectを継承して作ったので、Field::Selectにcollectionで値を渡してやる時のように[label, value]で渡してやればいいです。
これでapp/views/fields/category_field/_form.html.erbのセレクトボックスにcolorが表示されるようになりました。
当初はField::Selectを改造して実装していましたが、他でField::Selectを使いたくなった時に困るのでカスタムフィールドを作成することにしました。
今後も、標準のfieldでは対応するのが難しいものがあるようであれば、カスタムフィールドを作成してしまうのが良いのではないかと思います。
楽天APIで取得した商品画像を表示する。
楽天APIを使って取得した商品画像のURLをDBに保存して使ってます。
管理画面でも保存されている画像を確認したかったので表示させることにしました。
同じ要領でCarrierWave等の他のファイルアップローダーを使っている時のファイルの表示もさせられるかなと思います。
これもカスタムフィールドを作成しました。
rails g administrate::field image
今回はapp/fields/image_field.rbは生成されたまま使います。
app/views/fields/image_field/_index.html.erbとapp/views/fields/image_field/_show.html.erbを編集します。
<%= image_tag field.to_s if field.to_s.present? %>
これで保存されている画像が表示されるようになります。
to_sはカスタムフィールドを生成したときに一緒に作られてるカスタムロジックです。
中身はdataのみで、保存されているデータを表示するために使います。
なくてもいいかなとは思いますが、基本的にはこれをそのまま使えば良いと思います。
コントローラーに独自アクションを追加
楽天APIの商品検索と結果の保存を管理画面でやれるようにしたかったので、検索用のsearchアクションをコントローラーに追加しました。
アクションの定義自体は普通にRailsのコントローラーでやるようにやればOKです。
で、config/rutoutes.rbのadministrateが自動で追加したところに、下記のように作ったアクションを追加します。
namespace :admin do
resources :bookmarks
resources :brands
resources :likes
resources :products do
get :search, on: :collection # 普段通りにgetで追加する。
end
resources :reviews do
delete :images, on: :member, action: :destroy_image
end
resources :users do
delete :avatar, on: :member, action: :destroy_avatar
end
root to: "reviews#index"
end
見てわかるように、普通にRailsでやるようにやればOKです。
AdministrateはDSLを使っていないので、カスタマイズ時にいつものやり方で対応していけるのが初学者的には助かるなと思いました。