Railsでは、標準で用意されているモデルのバリデーションの他に、カスタムバリデーションメソッドを作成することで、独自のバリデーションを行えます。
6 カスタムバリデーションを実行する | Active Record バリデーション - Railsガイド
そんな中、「カスタムバリデーションメソッドは作るけど、そこで発生するバリデーションエラーは標準で用意されているものを使いたい」場合に、どのようにすればよいか悩んだため、メモを残します。
目次
環境
- Rails 7.0
調査
カスタムバリデーションメソッドでは、 errors.add()
メソッドを使うことでエラーメッセージを設定できます。
7.4 errors.add | Active Record バリデーション - Railsガイド
このメソッドの定義を見たところ、引数として
- attribute
- 属性名
- type
- 文字列 or シンボル or Proc
- **options
がありました。
https://api.rubyonrails.org/v7.0/classes/ActiveModel/Errors.html#method-i-add
type
にシンボルを渡した場合は、以下のように書かれていました。
If
type
is a symbol, it will be translated using the appropriate scope (seegenerate_message
).person.errors.add(:name, :blank) person.errors.messages # => {:name=>["can't be blank"]} person.errors.add(:name, :too_long, { count: 25 }) person.errors.messages # => ["is too long (maximum is 25 characters)"]
次に generate_message
のドキュメントを読むと、定義されているシンボルを渡せば良さそうに見えました。
Translates an error message in its default scope (
activemodel.errors.messages
).https://api.rubyonrails.org/v7.0/classes/ActiveModel/Errors.html#method-i-generate_message
次に、定義されているシンボルを調べたところ、以下にありました。
4.5.2 エラーメッセージ内での式展開 | Rails 国際化(i18n)API - Railsガイド
これで必要な情報が集まったため、次は検証をしてみます。
検証
いくつかのパターンでどのように実装が異なるかを試してみます。
エラーメッセージの引数が不要な場合
シンボル :blank
を使った、カスタムバリデーションメソッドを持つモデルを用意します。
class Shop < ApplicationRecord validate :validate_name private def validate_name return if name.present? errors.add(:name, :blank) end end
Railsコンソールで試してみたところ、標準のエラーメッセージが表示されました。
>> shop = Shop.new (1.2ms) SELECT sqlite_version(*) => #<Shop:0x00007fad5cfd9bc8 id: nil, name: nil, created_at: nil, updated_at: nil> >> shop.valid? => false >> shop.errors.full_messages => ["Name can't be blank"]
エラーメッセージの引数が必要な場合
シンボル :wrong_length
では引数 count
が必要になるため、これを引数のシンボルとして使ってみます。
class Shop < ApplicationRecord validate :validate_name private def validate_name return if name.present? errors.add(:name, :wrong_length, count: 5) end end
Railsコンソールで確認すると、引数の値がメッセージに反映されていました。
>> shop = Shop.new (1.8ms) SELECT sqlite_version(*) => #<Shop:0x00007fb234ad94c0 id: nil, name: nil, created_at: nil, updated_at: nil> >> shop.valid? => false >> shop.errors.full_messages => ["Name is the wrong length (should be 5 characters)"]
標準のバリデータで、標準メッセージを別の標準メッセージに差し替える
Blogタイトルとは異なりますが、標準バリデータのメッセージを標準に差し替えることも試してみます。
Railsガイドによると、 message
オプションを使えば良さそうでしたので、試してみます。
3.3 :message | Active Record バリデーション - Railsガイド
モデルを変更します。
class Shop < ApplicationRecord validates :name, presence: { message: :wrong_length, count: 4 } end
Railsコンソールで確認したところ、メッセージが差し替わっていました。
>> shop = Shop.new (1.0ms) SELECT sqlite_version(*) => #<Shop:0x00007f9c02589148 id: nil, name: nil, created_at: nil, updated_at: nil> >> shop.valid? => false >> shop.errors.full_messages => ["Name is the wrong length (should be 4 characters)"]
ソースコード
Githubに上げました。