3

我有一个模型,根据其当前状态需要不同的验证器。我应该如何为每个实例调用 ActiveRecord 验证器?我想尽可能多地重复使用管道,但我不确定如何继续。

class Order < ActiveRecord::Base
  attr_accessible :state

  validate :state_specific_validations

  def state_specific_validations
    if :paid == self.state
      # Warning: here be Unicorns...

      # Wishful thinking...
      validate_presence_of :paid_at
      validate_associated :purchaser

      # Hopeful. What are the validators called internally in Rails?
      errors << PresenceValidator.new(self, :paid_at).valid?
      errors << AssociationValidator.new(self, :paid_at).valid?

      # Plan B
      # ... Hoping for help from the audience ...

    else
      # Even more complicated validator logic, hoping for some DRY validators
    end
  end
end

我可以只使用自定义验证器,但为什么我需要复制所有内置验证器逻辑(i18n 错误消息等)?

有没有一种简洁的方法可以将 Rails 验证器作为实例方法调用?我认为 Sequel 的基于实例的验证器的方法比 ActiveRecord 的基于类的方法更合理,但我不在这里判断。我只是想回到解决更有趣的问题。我只是希望其他人已经遇到过这个问题,并且可以为我指出一些有趣的要点或宝石。

4

2 回答 2

4

我很确定所有validate_*方法都可以选择一个:if选项 - 它可以指向另一种方法(并且可能也接受 Proc),因此您可以将验证分解为更像:

validates_presence_of :paid_at, :if => :paid?
validates_association :purchaser, :if => :paid?

为了进一步清理,有 with_options 助手:

with_options :if => :paid? do |v|
  v.validates_presence_of :paid_at
  v.validates_association :purchaser
end

不确定是否可以与标准一起使用validate :custom_validate_method-但这不会让我感到惊讶。

于 2011-08-15T10:04:52.090 回答
0

有什么理由不合适吗?看起来它可能会起作用,但也许元编程扭曲了我的大脑......

class Order < ActiveRecord::Base
  attr_accessible :state

  validate :state_specific_validations

  def state_specific_validations
    if :paid == self.state
      class << self
        validate_presence_of :paid_at
        validate_associated :purchaser
      end
    end
  end
end

最糟糕的是测试通过了,所以我不确定我是否解决了它或者我需要更好的测试。例如,我不是 100% 肯定这个单例修改不会影响其他订单。

叹息需要一些睡眠。

于 2011-08-17T19:20:31.037 回答