如何在rails中动态添加自定义验证程序?

时间:2015-07-24 16:07:28

标签: ruby-on-rails

我有一个案例需要为同一个对象的不同实例添加和删除自定义验证器。

例如......

class MyCustomValidator < ActiveModel::Validator
 ...
end

class Foo
  include ActiveModel::Validations
  validates_with MyCustomValidator
end

背景A:

Foo.new.valid? #=> This should use the custom validator

背景B:

f = Foo.new
f.class.clear_validators!
f.valid? #=> This should no longer call the custom validator

背景C:

f = Foo.new
f.class.clear_validators!
f.valid? #=> This should no longer call the custom validator


# This is where I need to do something to bring the validator back so I can run


f.valid? #=> This should use the custom validator

有没有办法实现这个目标?

2 个答案:

答案 0 :(得分:0)

您可以执行以下操作:

class Foo
  include ActiveModel::Validations
  validates_with MyCustomValidator, if: :use_custom_validators?

  def use_custom_validators?
    !@custom_validator_disabled
  end

  def without_custom_validators(&block)
    prev_disabled, @custom_validator_disabled = @custom_validator_disabled, true
    @custom_validator_disabled = true
    instance_eval(&block)
    @custom_validator_disabled = prev_disabled
  end

end

f = Foo.new
f.valid?      # Custom validator used
f.without_custom_validators do
  valid?      # Custom validator not used
end
f.valid?      # Custom validator used

答案 1 :(得分:0)

如果使用验证器的必要性由对象的某些状态定义,则可以使用state_machine gem并明确定义状态标志。之后,您可以定义state-specific validations

要使其工作,您需要定义两个状态,并在其中一个状态上定义额外的验证。然后,您需要创建一个从“干净”状态转换为“已验证”状态的事件(或任何您称之为的状态)。

示例:

class LockableSwitch < ActiveRecord::Base
  state_machine initial: :off
    state :off # It's probably redundant. I dunno.
               # if you're not storing state as strings, you'd specify
               # state :off, value: 0 # if `state` column was an integer
    state :on do
      # Can only be switched on if a key is inserted
      validates :key, presence: true
    end

    event :switch do # An event that causes the apple to become ripe
      transition :off => :on # `=>` justifies the use of that old syntax
      transition :on => :off # The first matched transition is used
    end
  end
end

@l = LockableSwitch.new # :off by default
@l.switch! # fails, bang-method throws an error on failed transition
@l.key = "something"
@l.switch! # works

它是另一个库和额外的内存/复杂性(即使不是太多),但它使你的代码在“它的作用”中更加清晰。