概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: Encapsulate each validation error as an Error object | Saeloun Blog
- 原文公開日: 2020/06/17
- 著者: Alkesh Ghorpade
- サイト: Saeloun
Rails: 個別のバリデーションエラーをErrorオブジェクトにカプセル化する(翻訳)
モデルのsave
、create
、update
アクションが失敗した場合のRailsのerrors
の表現方法が#32313で変更されました。
変更前
たとえばUser
というモデルがあり、そこにfirst_name
、last_name
、contact_number
、email
などのカラムがあり、どれも必須だとしましょう。User
オブジェクトを作成するときにfirst_name
やcontact_number
をstring
として渡さないと、#errors
関数が以下のようなエラーを出力します。
class User < ApplicationRecord
validates :contact_number,
presence: true,
numericality: true,
length: { :minimum => 10, :maximum => 15 }
end
user = User.create(email: "sam@example.com", last_name: "Example", contact_number: "abcdefghijk")
user.errors
=> #<ActiveModel::Errors:0x00007fe42c1650b8
@base=
#<User:0x00007fe42c1676d8
....
....
@details={:first_name=>[{:error=>:blank}], :contact_number=>[{:error=>:not_a_number}]}
@messages=
{:first_name=>["First Name is required."],
:contact_number=>["Contact number is not a number."]
}>
特定のフィールドに関するエラーメッセージは以下のように[]
メソッドでアクセスできます。
user.errors[:first_name]
=> ["First Name is required."]
#messages
や#full_messages
ですべてのエラーメッセージのリストを表示することもできます。
user.errors.messages
{
:first_name=>["First Name is required."],
:contact_number=>["Contact number is not a number."]
}
user.errors.full_messages
[
"First name is required.",
"Contact number is not a number."
]
エラーへのアクセスを上のように行うのはオブジェクト指向的ではありません。この方法では、特定のフィールドに関連付けられているエラーが複数ある場合に配列インデックスでアクセスしなければならなくなります。
user = User.create(email: "sam@example.com", last_name: "Example")
user.errors[:contact_number]
#=> ["Contact Name is required.", "Contact Name is not a number."]
user.errors[:contact_number][0]
#=> "Contact Name is required."
user.errors[:contact_number][1]
#=> "Contact Name is not a number."
変更後
最近のActiveModel#errors
の変更によって、上のエラーはハッシュではなくErrorクラスのオブジェクトとして出力されます。
user = User.create(email: "sam@example.com", last_name: "Example", contact_number: "abcdefghijk")
user.errors
#=> #<ActiveModel::Errors:0x00007ff5ba2be5a0 @base=#<User id: nil, first_name: nil, last_name: "Example", email: "sam@example.com", contact_number: "abcdefghijk", created_at: nil, updated_at: nil>,
@errors=[<#ActiveModel::Error attribute=first_name, type=blank, options={}>, <#ActiveModel::Error attribute=contact_number, type=not_a_number, options={:value=>"abcdefghijk"}>]>
where
句を用いると、特定の属性に関連するエラーをフェッチできます。
user.errors.where(:contact_number)
#=> [<#ActiveModel::Error attribute=contact_number, type=not_a_number, options={:value=>"abcdefghijk}>]
where => (attribute, type, options)
とシグネチャが似ているadd
、added?
、delete
、match?
といったメソッドも利用できます。
user.errors.add(:contact_number, :too_short, count: 10)
#=> <#ActiveModel::Error attribute=contact_number, type=too_short, options={:count=>10}>
user.errors.where(:contact_number)
#=> [<#ActiveModel::Error attribute=contact_number, type=not_a_number, options={:value=>nil}>, <#ActiveModel::Error
attribute=contact_number, type=too_short, options={:count=>10}>]
user.errors.added?(:contact_number, :too_short, count: 10)
#=> true
user.errors.added?(:contact_number, :too_short)
#=> false
user.errors.delete(:contact_number, :too_short, count: 10)
user.errors.where(:contact_number)
#=> [<#ActiveModel::Error attribute=contact_number, type=not_a_number, options={:value=>nil}>]
user.errors.match?(:contact_number, :not_a_number)
#=> true
user.errors.match?(:contact_number, :too_long)
#=> false
このように、added?
メソッドで指定の属性に特定のエラーが発生しているかをチェックできます。
この変更によって、message
メソッドやfull_message
メソッドでwhere
句を用いてアクセスできるようになりました。
user.errors.where(:first_name, :blank).last.message
#=> "can't be blank"
user.errors.where(:contact_number, :not_a_number).last.full_message
#=> "Contact number is not a number"
メモ
以下のメソッドは非推奨化されました。利用するとdeprecation warningが表示されます。
[]
each{|attr, msgs|}
generate_message
has_key?
key?
keys
values
user.errors.keys
DEPRECATION WARNING: ActiveModel::Errors#keys is deprecated and will be removed in Rails 6.2.
To achieve the same use:
errors.attribute_names
以下のメソッドは変更されていません。
as_json
、blank?
、clear
、count
、empty?
add
added?
full_messages
full_messages_for
include?
、size
、to_hash
、to_xml
、to_a
messages
details