アルパカログ

Webエンジニアでマネージャーな人がプログラミングやマネジメントの話題を中心に書いているブログです。

Ruby on Rails カスタムバリデーションのエラーメッセージを翻訳する

f:id:otoyo0122:20200815100706p:plain:w300

Ruby on Railsでは、カスタムバリデーションを使って独自のバリデーションを追加することができます。

しかし既存のバリデーションと違い、カスタムバリデーションではi18nによる翻訳を自分で追加しなければなりません。

このエントリではRuby on Rails 5において、カスタムバリデーションのエラーメッセージerrors.full_messagesの翻訳を追加する方法を説明します。

エラーメッセージのロケール

通常、モデルのバリデーションは次のようにロケールファイルを定義しておくことでerrors.full_messagesが翻訳された状態で得られます。

ja:
  errors:
    messages:
      blank: を入力してください
      taken: はすでに存在します
    full_messages:
      format: "%{attribute}%{message}"
  attributes:
    email: メールアドレス

例えばuser.emailフィールドがpresence: trueでエラーになった場合は、blankにあたる「メールアドレス を入力してください」というエラーメッセージになります。

uniqueness: trueの場合はtakenです。

他のバリデーションと翻訳の対応は下記から探してください。

カスタムバリデーションクラスの定義

Ruby on Rails 5で独自のカスタムバリデーションを追加するためには、ActiveModel::ValidatorまたはActiveModel::EachValidatorを継承したValidatorクラスを実装します。

Ruby on Railsガイドには次のような例が載っています。

class MyValidator < ActiveModel::Validator
  def validate(record)
    unless record.name.starts_with? 'X'
      record.errors[:name] << '名前はXで始まる必要があります'
    end
  end
end
 
class Person
  include ActiveModel::Validations
  validates_with MyValidator
end
class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
      record.errors[attribute] << (options[:message] || "はメールアドレスではありません")
    end
  end
end
 
class Person < ApplicationRecord
  validates :email, presence: true, email: true
end

どちらもrecord.errorsにエラーメッセージそのものを追加しています。

この方法では当然、i18nで翻訳することはできません。

errors.full_messagesを翻訳された状態で得るにはaddメソッドを使って次のようにします。

class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
      record.errors.add(attribute, :not_email_format)
    end
  end
end

addメソッドの第1引数はオブジェクトの属性です。

ActiveModel::Validatorを継承しているなら対象の属性名のシンボル(:email:name)としてください。

第2引数の:not_email_formatに対応する翻訳をロケールのerrorsに追加します。

ja:
  errors:
    messages:
      blank: を入力してください
      taken: はすでに存在します
      not_email_format: がメールアドレスの形式ではありません

このようにしておくことでEmailValidatorに引っかかったとき、errors.full_messagesが翻訳された状態で得られます。

この例ですと「メールアドレス がメールアドレスの形式ではありません」となります。

以上です。

このエントリではRuby on Rails 5において、カスタムバリデーションのエラーメッセージerrors.full_messagesの翻訳を追加する方法を説明しました。

参考になった方は、ぜひ「はてブ」やSNSでシェアしていただければ嬉しいです。