Rails模式的动态最小/最大值验证

时间:2015-09-22 10:24:18

标签: ruby-on-rails validation ruby-on-rails-4

我使用长度验证器作为模型并且工作正常。

validates :my_field, length: {minimum: 10, maximum: 100}

我试图动态使用该值。例如,我想从Preference模型中获取值。

validates :my_field, length: {minimum: Preference.int_value("my.minimum"), maximum: Preference.int_value("my.maximum")}

在更改Preference模型的值之前,此代码正常工作。 如果我将值从10更改为5,则不会影响模型验证的结果。

似乎验证方法已加载到内存中,修复服务器启动时的值

如何执行动态长度验证?

1 个答案:

答案 0 :(得分:0)

这是一个自我回答。

我创建了一个自定义验证器,它继承了内置长度验证器和覆盖超类的两种方法,使验证器可以接受 lambda 作为值。这使得验证器可以在运行时call 阻止

class MyLengthValidator < ActiveModel::Validations::LengthValidator

  def check_validity!
    keys = CHECKS.keys & options.keys

    if keys.empty?
      raise ArgumentError, 'Range unspecified. Specify the :in, :within, :maximum, :minimum, or :is option.'
    end

    keys.each do |key|
      # !!!!! Here is the point that I've customized !!!!!
      value = options[key].is_a?(Proc) ? options[key].call : options[key]

      unless (value.is_a?(Integer) && value >= 0) || value == Float::INFINITY
        raise ArgumentError, ":#{key} must be a nonnegative Integer or Infinity"
      end
    end
  end

  def validate_each(record, attribute, value)
    value = tokenize(record, value)
    value_length = value.respond_to?(:length) ? value.length : value.to_s.length
    errors_options = options.except(*RESERVED_OPTIONS)

    CHECKS.each do |key, validity_check|

      # !!!!! Here is the point that I've customized !!!!!
      next unless check_value = options[key].is_a?(Proc) ? options[key].call : options[key]

      if !value.nil? || skip_nil_check?(key)
        next if value_length.send(validity_check, check_value)
      end

      errors_options[:count] = check_value

      default_message = options[MESSAGES[key]]
      errors_options[:message] ||= default_message if default_message

      record.errors.add(attribute, MESSAGES[key], errors_options)
    end
  end

end

并将lambda作为自定义长度验证器选项的值传递:

validates :my_field, my_length: {
   minimum: -> { Preference.int_value("my.minimum") }, 
   maximum: -> { Preference.int_value("my.maximum") } 
}

您可以在需要时参考此已关闭的公关:https://github.com/rails/rails/pull/21730/files