Help us understand the problem. What is going on with this article?

Ruby On Rails のValidation メッセージをカスタマイズする

More than 1 year has passed since last update.

背景

Railsの多言語化にはi18nがよく利用されます。

通常下記のように設定をしますよね

config/locales/*.yml
ja:
  activemodel:
    # モデル名
    models:
      user: "ユーザー"
      attributes:
        # モデル毎の属性名
        user:
          name: "名前"
    # 共通の属性名
    attributes:
      gender: "性別"
  # バリデーションエラー
  errors:
    # テンプレート
    format: "%{attribute}%{message}"
    # エラー毎のメッセージ
    messages:
      blank: "を入力してください"
en:
  # 同じ構造なので略
User.rb
class User < ApplicationRecord
  validates :name, presence: true
end

この時、フォームでnameに空白のままsubmitを実行すると、名前を入力してくださいと表示されます。

ですが、例えばnameが空白の時に名前はフルネームで入力してくださいとか、名前は姓・名で分けてくださいと表示したかった場合どうしますか?

*.ymlmodels.attributes.user.nameerrors.messages.blankを書き換える力技もありますが、これでは保守性0です。

美しくありません。また、

User.rb
class User < ApplicationRecord
  validates :name, presence: { message: '名前はフルネームで入力してください' }
end

上記も悪くないけど、多言語化に対応できていない。

そこで、i18nを用いた、メッセージのカスタマイズ方法を紹介いたします。

解決策

Procを組み合わせます。lambdaでも可能です。

config/locales/*.yml
ja:
  activemodel:
    # 同じ構造なので略
  # バリデーションエラー
  errors:
    messages:
      blank: "を入力してください"
    models:
      user:
        fullname_blank: "名前はフルネームで入力してください"
en:
  # 同じ構造なので略
User.rb
class User < ApplicationRecord
  validates :name, presence: {
    message: -> (rec, data) {
      I18n.t('activemodel.errors.models.user.fullname_blank')
    }
  }
end

これを実行すると、うまく多言語化されると思います。

ちなみに、Procを使わないとうまく多言語化されないので気をつけてください。下記が悪い例です。

User.rb
class User < ApplicationRecord
  validates :name, presence: {
    message: I18n.t('activemodel.errors.models.user.fullname_blank')
  }
end

参考

hiyoko3
A Software developer in Tokyo.
https://hiyoko3.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away