使用ActiveModel验证验证子对象

时间:2013-05-23 04:15:41

标签: ruby-on-rails-3 validation activemodel

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

  1. 新帐户
  2. 必须存在关联的联系人
  3. 相关联系人必须有效(即account.contact.valid?)
  4. 看起来ActiveModel不再包含validates_associated方法,因为使用该方法会导致未定义的方法错误。我考虑过要求ActiveRecord :: Validations,但这导致了一系列各种错误(例如,未定义的方法`marked_for_destruction?')

    我还考虑过在Account类上定义验证并调用有效吗?在关联对象上,但只有在父对象上也存在错误时才阻止表单提交。

    validate do |account|
      account.contact.valid?
    
      # required for form to fail
      errors.add(:base, "some error")
    end
    

    有什么东西我不知道要解决这个问题吗?感谢。

2 个答案:

答案 0 :(得分: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,条件不会被短路。

答案 1 :(得分:1)

最近(问了这个问题已有7年了!),我遇到了同样的问题,并通过基于ActiveRecord的AssociatedValidator实现了解决。 我只是将其包含在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

现在您也可以在ActiveModel中使用validates_associated