我使用长度验证器作为模型并且工作正常。
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,则不会影响模型验证的结果。
似乎验证方法已加载到内存中,修复服务器启动时的值。
如何执行动态长度验证?
答案 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