【问题标题】:Dynamic minimum/maximum values for Rails mode validatesRails 模式的动态最小值/最大值验证
【发布时间】:2015-12-19 06:54:07
【问题描述】:

我正在为模型使用长度验证器,它工作正常。

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,则不会影响模型验证的结果。

validates 方法似乎已加载到内存中,并在服务器启动时修复该值

如何执行动态长度验证?

【问题讨论】:

  • 您可以随时使用自定义验证,但这肯定不是答案,我很想知道验证是如何加载的
  • 尝试使用 Proc 动态处理它。类似length: {minimum: Proc.new {Preference.int_value("my.minimum")}, ...
  • @dimuch 看起来不像 minimummaximum 可以是用于长度验证的 Proc
  • 是的,没错。它在 greater_than / less_than 中运行良好,但在 minimum 中失败

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


【解决方案1】:

这是一个自我回答。

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

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") } 
}

需要时可以参考这个已关闭的 PR:https://github.com/rails/rails/pull/21730/files

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-07-06
    • 2019-02-09
    • 2021-04-16
    • 2018-02-07
    • 1970-01-01
    • 1970-01-01
    • 2017-07-09
    • 2013-11-15
    相关资源
    最近更新 更多