Posted at

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


背景

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


参考