LoginSignup
6
4

More than 1 year has passed since last update.

Rails7とInfoldを使って管理画面を素早く作る

Last updated at Posted at 2022-12-06

はじめに

Railsエンジニアの皆さん、管理画面作るときはどうしていますか?
ActiveAdminなどの管理画面系Gemを使うのも手ですが、

  • DSLでカスタマイズするのが辛い
  • 欲しい機能が実現できないことがある
  • デザインがあまり好みでない

私個人はこんな理由で、既存のGemは使わず、イチから開発していました。しかし、都度イチから開発するのは非効率ですし、管理画面は共通化できる要素が多いことも特徴です。
そこで、自作フレームワークを作って開発を効率化してきました。この仕組みが私自身の開発を大きく改善できたので、是非みなさんにも共有したいと思い、Gemにして公開しました。

今回はこのGem Infold の使い方をご紹介いたします。

どんなツール?

まずは こちらのデモサイト をご参照ください。
このアプリは、 Gemから自動生成した機能だけで構築 しています。

ツールの特徴

以下をテーマとして開発をしています。

  1. コードを自動生成する
  2. DSLは使わない
  3. モダンで使い勝手の良いUI/UX

1. コードを自動生成する

といってもGithub Copilotのような代物ではなく、RailsのScaffoldを拡張しています。Scaffoldはリソースの定義をするだけで、controller, model, viewなどのファイルが自動で生成されてCRUDできる基本機能が自動で出来上がります。この仕組みを応用して、管理画面に特化したジェネレータを開発しました。

また、生成されるコードは、可読性を重視しています。ただ動けばよいのではなく、生成されたコードをエンジニア自身が容易に可読でき、追加のカスタマイズがしやすい仕組みを目的としています。

2. DSLは使わない

設定はDSLではなくYAMLに記載します。このYAMLを上記のジェネレータに読み込ませると、設定に応じたCRUDアプリのコードを自動生成できます。

YAMLなのでDSLのようにロジックをゴリゴリ書くことはできませんが、シンプルでわかりやすいことを重視しています。全ての機能をGemとDSLで実現するのではなく、無理なく共通化できるレベルまでを自動生成し、追加のカスタマイズは通常のRails開発と同様にできたほうがよいと考えています(なので、コードを自動生成する仕組みを採用しています)

とはいえ、YAMLだけでもそれなりの機能性を実現しています。デモサイトでも実装していますが、例えば以下のような機能性があります。

  • has_many なデータの一括登録・参照
  • Validation, Enum, Decoratorなどの仕組み
  • 画像ファイルの登録や、CSVファイルの出力、などなど

3. モダンでユーザビリティの高いUI/UX

Hotwireを利用して、SPAライクなUI/UXを実現しています。また、UIのテンプレートにはBootstrap5をベースにした tabler を採用しています。これにより、モダンでユーザビリティの高い管理画面を実現しています。

管理画面の開発には、デザイナーの方は参画せず、エンジニアだけで画面のUIを含めて構築することが多いかと思います。画面周りが苦手なエンジニアの方だけでも、ユーザビリティに優れた管理画面を実現できることを目指しています。

対応するRailsのバージョン

  • Hotwireでの動作を想定していることから、Railsは7.0以上で動作します
  • また、Railsはesbuild等でJSのビルド環境が必要となります

実際の使い方

前置きが長くなりましたが、ここからはインストールから実際のカスタマイズまでをご説明します。

Infoldのインストール

Gemfileに[infold]と、infoldで利用している各種Gemを追記し、 bundle install します。

Gemfile
gem 'infold', require: false
gem 'devise'           # 認証
gem 'haml-rails'       # HAML
gem 'kaminari'         # ページネーション
gem 'view_component'   # View Component
gem 'active_decorator' # Decoration
gem 'enum_help'        # Enum Helpers

次に、infoldのジェネレータからインストールをします。

$ rails generate infold:install

このタイミングで、view_componentやstimulusなどで利用する共通的なファイルが生成されます。
また、Deviseのマイグレーションも生成されますので、テーブルの作成と、rails consoleからテスト用アカウントの登録をしておきます

$ rails db:migrate
$ rails console

AdminUser.create(email: 'user@example.com', password: 'password')

以上でインストールは完了です。このタイミングで bin/dev からRailsを起動後、ブラウザで http://localhost:3000/admin にアクセスすると、ログイン画面が表示されるので、先程作成したユーザー情報でログインします。
01_installed.png
これでログイン機能が作れました。続けて、実際にアプリを構築していきます。

顧客管理アプリの作成

まずは顧客(Customer)モデルを作成します。ここでは通常のRailsのgenerate modelを使います。

$ bin/rails g model Customer name:string address:string gender:integer
$ bin/rails db:migrate

infoldのジェネレータを使って、このモデルに対するアプリを作成します。

$ bin/rails g infold Customer

これだけで顧客管理アプリが生成されています。この段階でブラウザからlocalhost:3000/admin/customers にアクセスすると、CUSTOMERSアプリが表示されます。
04_customer_search.png
画面右上のオレンジ色のボタン「Create New」をクリックするとフォームが表示されます。適当に入力して画面右下の青色のボタン「Create」から登録ができます。
03_customer_form.png
レコードの左端「ノートアイコン」から参照画面、右端「鉛筆アイコン」から編集画面が表示されます。
05_customer_show.png
ほんの数ステップで、CRUDをベースとした管理画面アプリが生成することができました。

このタイミングでControllerやViewなどのファイルが自動で生成されています。例えばControllerは app/controllers/admin/customer_controller.rb が以下の通り生成されています。
image.png
このように、InfoldはActiveAdminのようにアプリそのものの生成ではなく、ソースコードを生成し、それを動作させる仕組みになっています。また、コードは一般的なRailsで書かれているので、Railsエンジニアの方であれば編集が容易にできます。ツールだけで実現できないカスタマイズは、このコードを直接編集することで、柔軟な対応が可能になります。

顧客管理アプリのカスタマイズ

上記で生成したアプリは、YAMLで設定をすることでカスタマイズができます。試しに以下の機能を追加してみます。

  • Nameを必須項目にする
  • Genderは male, female, other のEnumとし、ラジオボタンから選択する

前述の rails g infold Customer のタイミングで、プロジェクトの config/infold/customer.yml が生成されています。このファイルを以下の内容に変更してください。

config/infold/customer.yml
model:
  validate:
    name: presence
  enum:
    gender:
      male: 1
      female: 2
      other: 3
app:
  form:
    fields:
      - name
      - address
      - gender:
          kind: radio

YAMLの編集後、改めて g infold を実行します。

$ bin/rails g infold Customer

これで、YAMLの設定に応じたコードが再生成されます。ブラウザから動作確認をしてご確認ください。バリデーションとラジオボタンのフォームが有効化されます。
07_customer_validate.png
このように、InfoldではYAMLを編集してカスタマイズを行います。

商品管理アプリの作成

続けて、商品管理を作成してみます。

Railsのモデル生成

$ bin/rails g model Product title:string price:integer
$ bin/rails db:migrate

infoldでアプリの生成

$ bin/rails g infold Product

ブラウザでlocalhost:3000/admin/products にアクセスすると、商品管理アプリが表示されます。ヘッダーメニューも「PRODUCTS」が追加されています。
08_products.png

商品画像の表示

InfoldはActiveStorageをサポートします。そこで、例えば商品画像を管理したい場合、config/infold/product.ymlを以下の設定にします。

config/infold/product.yml
model:
  active_storage:
    photo:
      kind: image
app:
  index:
    list:
      fields:
        - id
        - title
        - photo
        - price
  form:
    fields:
      - title
      - photo:
          kind: file
      - price

なお、プロジェクトでActiveStorageがインストールされていることが前提となります。

$ bin/rails active_storage:install
$ bin/rails db:migrate

infoldでアプリを生成します。

$ bin/rails g infold Product

上記設定で、フォームから画像が登録でき、一覧に表示されます。
09_product_image_form.png
10_product_images.png

注文管理アプリの作成

上記の「顧客」「商品」管理は、単一のテーブルをCRUDとしていましたが、次に作る「注文管理」は、顧客と商品のリレーションを設定していきます。
RailsからOrderモデルを作成します。

$ bin/rails g model Order customer:references product:references amount:integer
$ bin/rails db:migrate

以下のリレーションになります。
er1_ja.png
注文管理アプリをinfoldから生成します。g infold:resource とすることで、YAMLファイルのみの生成ができます。

$ bin/rails g infold:resource Order

Orderと他モデルにアソシエーションを設定するために、config/infold/order.yml を以下のように編集します。
なお、以下の ! 部分にある name_field は、レコードの名称を表すフィールドを指定します。その結果、関連先のレコードをそのフィールドで表示できます。例えば、orderモデルはcustomer_idを介してcustomerモデルとの関連を持ちますが、画面上では customer_id を表示する代わりに、customer.name を表示します。

config/infold/order.yml
model:
  association:
    customer:
      kind: belongs_to
      name_field: name # !
    product:
      kind: belongs_to
      name_field: title # !
app:
  form:
    fields:
      - customer:
          kind: select
      - product:
          kind: select
      - amount:
          kind: number

YAML編集後、Infoldのジェネレータでコードを生成します。

$ bin/rails g infold Order

ブラウザから確認すると、例えば登録フォームからは、CustomerやProductがリストから選択可能になっています。
11_order_form.png
また、Orderを登録後、Customer, Productはリンクで表示され、それをクリックすると詳細を参照できるようになります。
12_order_product.png

応用編

has_manyの一括登録

現状の注文管理は、OrderモデルがProductモデルに直接関連しているため( order belongs_to product)、一度の注文に一つの商品しか購入できません。複数商品をまとめて購入できるよう、OrderDetail を追加し、以下のモデリングに変更します( order has_many order_details, order_detail belongs_to product )。
er2.png
Rails側でモデルの変更・追加をしていきます。まず、OrderとProductの関連を除去するために、以下のマイグレーションを生成します。

$ bin/rails g migration RemoveProductFromOrders product:references amount:integer

また、Orderモデルにも belongs_to :product の記述が残っているので、削除します。

models/order.rb
class Order < ApplicationRecord
  belongs_to :customer
- belongs_to :product
end

次に、OrderDetailモデルを作成し、マイグレーションを実行します。

$ bin/rails g model OrderDetail order:references product:references amount:integer
$ bin/rails db:migrate

Infoldで注文管理 (config/infold/order.yml) を変更していきます。

config/infold/order.yml
model:
  ...
  association:
    customer:
      kind: belongs_to
      name_field: name
-   # 以下は削除
-   product:
-     kind: belongs_to
-     name_field: title
+   # 以下を追加
+   order_details:
+     kind: has_many
+     dependent: destroy
+     model: # 関連先モデル(order_details)の設定も可能
+       validate:
+         product: presence
+       association: # order_detailsの更に関連先(product)
+         product:
+           kind: belongs_to
+           name_field: title
app:
  # 参照画面にも一括表示するために以下を追加
+ show:
+   fields:
+     - id
+     - customer
+     - order_details:
+         fields:
+           - product
+           - amount
  form:
    fields:
      - customer:
          kind: select
-     # 以下は削除
-     - product
-         kind: select
-      - amount
-          kind: number
+     # 以下を追加
+     - order_details:
+         kind: association
+         fields:
+           - product:
+               kind: select
+           - amount:
+               kind: number

この状態でInfoldで注文管理アプリを再生成します。

$ bin/rails g infold Order

フォームで一括登録が可能になります。[ADD]ボタンをクリックすると行が追加され、行の右端「ゴミ箱アイコン」をクリックで削除できます。
13_order_details_form.png

子画面からの検索・指定

現状の注文管理(orders)の登録フォームでは、顧客(customer)がリストになっています。顧客データが多くなると、リストでは該当のレコードを指定することが困難になります(例えば顧客データが100件あったら、リストの選択肢も100件になり、使い物にならない)
Infoldでは、belongs_toによる関連モデルを、子画面から検索・指定できます。注文管理から顧客を子画面で指定するように変更してみます。

まず、顧客の子画面検索を有効化するために、顧客管理側のYAML (customer.yml) を編集していきます。

config/infold/customer.yml
model:
  ...
app:
  form:
    ...
+ # 以下を追加
+ association_search:
+   conditions:
+     - id:
+         sign: eq
+     - name:
+         sign: full_like
+   list:
+     fields:
+       - id
+       - name

次に、注文管理側のYAML (order.yml) を編集します(kindをselectからassociation_searchに変更)。

config/infold/order.yml
model:
  ...
app:
  form:
    fields:
      - customer:
-         kind: select
+         kind: association_search
      - order_details:
        ...         

顧客管理、注文管理、それぞれのコードをInfoldから再生成します。

$ bin/rails g infold Customer
$ bin/rails g infold Order

ブラウザで 注文管理の登録フォームを表示すると、顧客のフォームが変わっていることが確認できます。このフォームの青い虫眼鏡ボタンをクリックすると、子画面で顧客の検索画面が表示されます。
子画面上で検索をし、一覧の右端列「チェックアイコン」をクリックすると、該当の顧客が注文管理フォームに引き継がれます。
14_association_search.gif

日本語化

Infoldはi18nに対応しています。日本語表示をする場合、Railsのdefault_localeを ja に変更します。詳細はRailsガイドなどを参照ください。

一例として、config/initializers/locale.rb を以下の通り作成します。

config/initializers/locale.rb
I18n.config.available_locales = [:ja, :en]
I18n.default_locale = :ja
I18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]

また、rails-i18n から ja.yml をダウンロードして、config/localesへ設置してください。

その後、config/locales ディレクトリに、modelsディレクトリを作成し、その中にcustomer.ja.ymlを以下の内容で作成します。

config/locales/models/customer.ja.yml
ja:
  activerecord:
    attributes:
      customer:
        name: 氏名
        address: 住所
        gender: 性別

顧客管理の画面が日本語化されます(ボタンやメッセージ内容も日本語化されています)
15_locale1.png

なお、Enumの区分値を日本語化する場合は、以下の通りです。

config/locales/models/customer.ja.yml
ja:
  activerecord:
    attributes:
      customer:
        name: 氏名
        address: 住所
        gender: 性別
+ enums:
+   admin: # adminを挟む必要があります
+     customer:
+       gender:
+         male: 男性
+         female: 女性
+         other: その他

Enumも含めて日本語化ができました。
16_locale2.png

まとめ

長くなりましたが、Infoldの一連の使い方をご説明いたしました。

YAMLの設定だけでも、それなりの機能を生成できることが確認できたかと思います。
あとは、自動生成後のソースコードをカスタマイズする流れになります。

イチから実装する場合と比較して、管理画面の実装スピードをかなり高速化できると思いますので、是非ご利用を検討頂けたら幸いです!

今回の説明で使ったコード

上記で生成したアプリは、Githubにて公開しています。

6
4
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
6
4