🎃

【Rails】DBと連携しないモデル(Active Model)の日本語化対応

2022/09/27に公開

Railsでスケジュール通知アプリを個人開発しています。

https://torikomi.fly.dev/

このアプリで実装したお問い合わせフォームを例に、「DBに紐づかないモデル」の扱い方をまとめます。

環境

アプリは以下の環境で作成しています。

  • macOS 11.6.2
  • Ruby 3.1.2
  • Rails 7.0.3
  • PostgreSQL 14.4

DBと連携しないモデルでActive Recordの機能を使う

https://railsguides.jp/active_record_basics.html

Railsのモデルは通常ActiveRecord::Baseというクラスを継承しており、DBと連携して使います。このActiveRecord::Baseを継承したモデルであれば、バリデーションやアソシエーションなどの便利な機能を使うことができます。

一方、DBと連携しないモデルを設計したい場合は、ActiveRecord::Baseを継承しないクラスにする必要があります。

では、「DBとは連携しないけれども、Active Recordにあるような便利な機能は使いたい」……そんなときはどうすればいいのでしょうか?

https://railsguides.jp/active_model_basics.html

https://qiita.com/Esfahan/items/4954b0eb474a81b34258

実はそのようなケースもRailsは想定していて、ActiveModel::Modelincludeすると、ActiveRecord::Baseを継承していないクラスでも、Active Recordの機能の一部が使えるようになるのです。

下記が、DBと連携しないモデルの例(Inquiry)です。入力されたお問い合わせ内容はすぐにメールで送信するのでDBには保存しませんが、バリデーション機能は使いたいので、include ActiveModel::Modelとしました。

app/models/inquiry.rb
class Inquiry
  include ActiveModel::Model

  attr_accessor :email, :body

  validates :email, presence: true
  validates :body, presence: true, length: { maximum: 65535 }
end

関連するコントローラ、ルーティング、ビューは次の通りです。InquiriesControllerでは、createアクションの@incuiry.valid?の箇所で、フォームに入力された内容のバリデーションを行っています。

app/controllers/inquiries_controller.rb
class InquiriesController < ApplicationController

  def new
    @inquiry = Inquiry.new
  end

  def create
    @inquiry = Inquiry.new(inquiry_params)
    if @inquiry.valid?
      # ここにメール送信の処理を記述(省略)
      redirect_to root_path, success: 'お問い合わせを受け付けました'
    else
      flash.now[:error] = 'お問い合わせの受付に失敗しました'
      render :new
    end
  end

  private

  def inquiry_params
    params.require(:inquiry).permit(:email, :body)
  end
end
app/views/inquiries/new.html.slim
/ CSSは省略
- if @inquiry.errors.any?
  - @inquiry.errors.full_messages.each do |error_message|
   ul
     li
       = '- ' + error_message
h1
 | お問い合わせ
p
 | 下記のフォームに必要事項をご記入ください。
 br
 | 近日中にメールにて返信いたします。
= form_with model: @inquiry do |f|
  label
    span
      = Inquiry.human_attribute_name('email') + '(必須)'
  = f.text_field :email
  label
    span
      = Inquiry.human_attribute_name('body') + '(必須)'
  = f.text_area :body
  = f.submit '送信'
config/routes.rb
Rails.application.routes.draw do
  resources :inquiries, only: %i(new create)
end

Active Modelをincludeしたモデルの日本語化

Active Modelをincludeしたモデルの日本語化のやり方は、Railsガイドの「Rails 国際化(i18n)API」のページの、「Active Recordモデルで翻訳を行なう」の項に書いてあります。

https://railsguides.jp/i18n.html#active-recordモデルで翻訳を行なう

通常のActive Recordのモデルを日本語化するときは、訳文ファイルでja:のあとにactiverecord:という階層を作って日本語訳を記述しますが、Active modelをincludeしたモデルを日本語化するときは、activerecord:の部分をそのままactivemodel:に置き換えて日本語訳を記述すればOKです。

config/locales/activemodel/ja.yml
ja:
  activemodel:
    models:
      inquiry: 'お問い合わせ'
    attributes:
      inquiry:
        email: '返信用メールアドレス'
        body: 'お問い合わせ内容'

これで、Inquiry.human_attribute_name('email')が「返信用メールアドレス」を、Inquiry.human_attribute_name('body')が「お問い合わせ内容」を返すようになります。

実際に、アプリのお問い合わせフォームを表示させてみます。

フォームのラベルに日本語訳が表示されていますし、空の状態で「送信」ボタンを押すと、日本語化されたエラーメッセージが表示されました!

感想

Active Modelに関する記事はいくつかありましたが、その日本語化に関する情報はあまりなかったので書いてみました。

調べるついでに、Rails7では「Active ModelからActiveModel::APIが切り出された」という情報も発見しました。下記にリンクを貼っておきます。

https://techracho.bpsinc.jp/hachi8833/2022_01_28/114954

Discussion