3

我有两个普通的 Ruby 类,Account 和 Contact。我正在使用 Simple Form 的 simple_form_for 和 simple_fields_for 创建嵌套属性。我希望满足以下验证要求:

  1. 新帐户必须存在关联的联系人
  2. 关联的联系人必须有效(即 account.contact.valid?)

看起来 ActiveModel 不再包含 validates_associated 方法,因为使用该方法会导致未定义的方法错误。我考虑过需要 ActiveRecord::Validations,但这导致了一系列错误(例如,未定义的方法 `marked_for_destruction?')

我还考虑在 Account 类上定义 validate 并调用 valid? 在关联对象上,但这只会在父对象上也有错误时阻止表单提交。

validate do |account|
  account.contact.valid?

  # required for form to fail
  errors.add(:base, "some error")
end

有什么我不知道来解决这个问题吗?谢谢。

4

2 回答 2

2

我最近(在提出这个问题 7 年后!)遇到了同样的问题,并通过实施AssociatedValidator基于 ActiveRecord 的方法解决了这个问题。我只是将它包含在config/initializers文件夹中:

module ActiveModel
  module Validations
    class AssociatedValidator < ActiveModel::EachValidator
      def validate_each(record, attribute, value)
        if Array(value).reject { |r| valid_object?(r) }.any?
          record.errors.add(attribute, :invalid, **options.merge(value: value))
        end
      end

      private

      def valid_object?(record)
        record.valid?
      end
    end

    module ClassMethods
      def validates_associated(*attr_names)
        validates_with AssociatedValidator, _merge_attributes(attr_names)
      end
    end
  end
end

现在你也可以validates_associated在 ActiveModel 中使用了。

于 2020-09-01T20:32:32.643 回答
1
class Person
  include Virtus
  include ActiveModel::Model

  attribute :address, Address, :default => Address.new

  validate :address_valid

  private

  def address_valid
    errors.add(:base, 'address is not valid') unless address.valid?
  end
end

class Address
  include Virtus::ValueObject
  include ActiveModel::Validations

  attribute :line_1, String
  attribute :line_2, String

  validates :line_1, :presence => true
  validates :line_2, :presence => true
end

如果您将对象传递给,错误会显示在表单中simple_fields_for

 = form.simple_fields_for person.address do |af|      
   = af.input :line_1

另一种选择是覆盖valid?

def valid?
  super & address.valid?
end

请注意,如果第一个返回 false,则条件&不会&&短路。

于 2013-07-05T16:10:19.627 回答