💎

【Rails】APIとシンプルな管理画面を提供する最小構成のプロジェクト作成

2023/10/05に公開

概要

APIとシンプルな管理画面を提供する最小構成のRailsプロジェクト作成について記述します。
最小には、Railsアプリケーションのスリム化と外部依存性を抑制する意図があります。

  • APIと管理画面を同一のRailsプロジェクトから提供します。
  • APIはcontrollerからjson/msgpackをrenderし、viewは使用しません。
  • 管理画面はviewでHTMLを出力します。
  • 管理画面のcss/jsはbootstrapなどの静的なファイルを用いる前提で、アセットパイプラインは使用しません。
  • デフォルトでインストールされるaction-mailer,active-storage,action-cableなどは使用しません。(requireしません。)

デフォルトのRailsプロジェクトはAPIサーバには多機能でAPIモードにしたいけど、管理画面ではHTMLを使いたいと思い、簡易な実装で試してみました。

環境

  • Apple M2 Pro
  • macOS 13.5.2(Ventura)
  • Ruby 3.2.2
  • Rails 7.0.8

プロジェクト作成

以下のコマンドでプロジェクトを作成しました。
APIモードで各種のインストールをスキップします。

rails new projectname \
--database=mysql \
--skip-action-mailer \
--skip-action-mailbox \
--skip-action-text \
--skip-active-job \
--skip-active-storage \
--skip-action-cable \
--skip-asset-pipeline \
--skip-javascript \
--skip-hotwire \
--skip-jbuilder \
--api

rails newのヘルプで各オプションの概要を確認できます。

rails new -h

Rails newのドキュメントはこちら。
Railsドキュメント

apiオプション

--apiオプションを指定することで、APIモードでRailsプロジェクトが作成されます。
APIモードの特徴は以下の通りです。

  • html,css,jsなどview関連のgemがインストールされません。
  • 使用するミドルウェアが絞り込まれます。
  • Controllerの基底クラスがActionController::BaseからActionController::APIに変更されます。

apiオプションの詳細はこちら。
Railsガイド

minimalオプション

--apiオプションとは別に最小構成でインストールを行う--minimalというオプションがあります。
以下のコマンドで冒頭に記載したプロジェクトと近しい構成になりましたが、Railsの起動を高速化するbootsnapが含まれませんでした。

rails new projectname --database=mysql --api --minimal

--no-skip-bootsnapを指定しても、--minimalが優先され、bootsnapは含まれませんでした。

rails new projectname --database=mysql --api --minimal --no-skip-bootsnap

bootsnapの有無による差分は以下の2点だったので、プロジェクトを作成した後でも追加しやすいです。

Gemfile
# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false
config/boot.rb
require "bootsnap/setup" # Speed up boot time by caching expensive operations.

APIモードでHTMLを出力するためにやったこと

APIモードでプロジェクトを作成した場合、そのままではviewを使用してHTMLを出力できません。
また、cookieやsessionも利用できません。
管理画面を開発するにあたり、以下の対応を行いました。

Controllerの基底クラスを変更した

APIと管理画面でControllerの基底クラスを分け、管理画面のControllerはActionController::Baseを継承しました。
これによりviewを使用してHTMLを出力できるようになりました。

app/controllers/admin/controller_base.rb
module Admin
  class ControllerBase < ActionController::Base
    layout 'admin'
  end
end

使用するmiddlewareを明示的に指定した

画面からの入力にform、処理結果の表示にflashを使用するため、以下のmiddlewareを明示的に使用しました。
管理画面の利用者が限定的なので、セッション管理にCookieStoreを使用しました。
ブラウザにセッション情報を保存する形ですが、セキュリティを強化する場合は、memcachedやredisでセッションを管理し、サーバーサイドに寄せることも可能です。

config/application.rb
    # Only loads a smaller set of middleware suitable for API only apps.
    # Middleware like session, flash, cookies can be added back manually.
    # Skip views, helpers and assets when generating a new resource.
    config.api_only = true
    config.middleware.use ActionDispatch::Flash
    config.middleware.use ActionDispatch::Cookies
    config.middleware.use ActionDispatch::Session::CookieStore

デフォルトのRailsプロジェクトと比較し、APIモードで利用されなかったmiddlewareは以下の通りです。

  • Rack::MethodOverride
  • Sprockets::Rails::QuietAssets
  • WebConsole::Middleware
  • ActionDispatch::Cookies
  • ActionDispatch::Session::CookieStore
  • ActionDispatch::Flash
  • ActionDispatch::ContentSecurityPolicy::Middleware
  • ActionDispatch::PermissionsPolicy::Middleware
  • Rack::TempfileReaper

静的なcss/jsを使用した

アセットパイプラインのインストールをスキップしているので、静的なcss/jsを使用します。
bootstrapあたりをlayoutsに含めておけば、フロントエンドが苦手でもそれっぽい感じの管理画面をさくっと作れます。

public
├── javascripts
│   └── bootstrap.min.js
├── robots.txt
└── stylesheets
    └── bootstrap.min.css
app/views/layouts/admin.html.erb
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title><%= content_for?(:title) ? yield(:title) : 'Admin Tool' %></title>
  <%= csrf_meta_tags %>
  <%= stylesheet_link_tag 'bootstrap.min' %>
  <%= yield :head %>
</head>
<body>
...
<%= javascript_include_tag 'bootstrap.min' %>
</body>
</html>

おわりに

APIモードでそれっぽい画面を出力することができました。
めでたしめでたし。

Happy Elements

Discussion