如何向 has_many 关联添加更有意义的错误消息?

Ccy*_*yan 5 error-handling ruby-on-rails

我的用户模型有很多这样的地址:

class User < ApplicationRecord
  has_many :addresses, dependent: :destroy
  accepts_nested_attributes_for :addresses, allow_destroy: true
end

class Address < ApplicationRecord
  belongs_to :user

  validates :address_line_1, :city, :state, :zip, presence: true
end
Run Code Online (Sandbox Code Playgroud)

Address模型还有一address_type列表示 aworkhome地址。

当我试图用错误保存两个地址时,我得到了一些对我来说似乎很奇怪的东西:

a = User.last
a.addresses # This user has both a home and work address
=>  #<ActiveRecord::Associations::CollectionProxy #<Address id: 1, address_line_1: "123 Bob St.", city: "Blah", zip: "12345", state: "KY", address_type: "home", user_id: "1">, #<Address id: 2, address_line_1: "123 Jane St.", city: "Bloh", zip: "12345", state: "KY", address_type: "work", user_id: "1">

a.assign_attributes(addresses_attributes: { "0" => { address_line_1: nil, id: 1 }, "1" => { address_line_1: nil, id: 2 } })
a.save # This is false
a.errors.details # Shows only 1 error
=> {:"addresses.address_line_1"=>[{:error=>:blank}]}
Run Code Online (Sandbox Code Playgroud)

从上面可以看出,当两个地址都无效时,Rails 只提供 1 个错误。我无法通过查看来判断两者是无效还是只有一个,并且我无法判断哪个有错误。有没有办法提供更详细的错误消息,可能是这样的:

{:"work_address.address_line_1"=>[{:error=>:blank}], :"home_address.address_line_1"=>[{:error=>:blank}]}
Run Code Online (Sandbox Code Playgroud)

或者至少包括对象 ID:

{:"addresses.address_line_1"=>[{:error=>:blank, :ids=>[1,2]}]}
Run Code Online (Sandbox Code Playgroud)

twn*_*ing 0

像这样的自定义验证怎么样?

validate :addresses_valid

def addresses_valid
  addresses.each.with_index(1) do |a, index|
    next if [a.address_line_1, a.city, a.state, a.zip].all?

    errors.add "address #{index}", "is invalid"
  end
end
Run Code Online (Sandbox Code Playgroud)

阅读更多Rails 指南验证