比方说,我有许多只能具有一组特定字符串值的属性。
通常,我们会看到以下内容。
class User < ApplicationRecord
validates :foo, inclusion: { in: ['some', 'array'] }
validates :bar, inclusion: { in: ['another', 'array'] }
validates :moo, inclusion: { in: ['one_more', 'array'] }
end
我的模型中有很多这类验证,我想将它们干燥。因此,我尝试了以下操作,但出现错误undefined method 'validates' for #User:0x00007fdc10370408
。
class User < ApplicationRecord
VALIDATION_ENUMS = {
foo: %w[foo1 foo2],
bar: %w[bar1 bar2]
}.freeze
validate :validate_enums
def validate_enums
VALIDATION_ENUMS.each_key do |attribute|
validates attribute, inclusion: { in: VALIDATION_ENUMS[attribute] }
end
end
end
如何从我的函数中访问ActiveModel :: Validations帮助器方法?
或者还有更好的方法吗?
[请记住,validates
是一个类方法,仅在加载该类以建立将被验证的内容时执行一次。 validate
正在调用实例方法。
更好的方法可能是在加载类时立即执行DRY代码。
class User < ApplicationRecord
validate_enums = {
foo: %w[foo1 foo2],
bar: %w[bar1 bar2]
}.freeze
validate_enums.each do |key, array|
validates key, inclusion: { in: array }
end
[请注意,由于您不再引用validate_enums
,因此无需使其成为类常量,这就是为什么我没有这样做。
但是您实际上并没有节省任何行数并增加了复杂性,所以我自己坚持使用明确的validates
。
这种方法不会成功。验证方法是在编写实例方法时修改类本身的类方法,该实例方法在调用#valid?
时将在类的实例上被调用。
如果要向类动态添加现有验证,则需要创建类方法:
class User < ApplicationRecord
def self.add_inclusion_validations(hash)
# don't use each_key if you're iterating over both keys and values
hash.each do |key, values|
validates_presence_of key, in: values
end
end
add_inclusion_validations(
foo: %w[foo1 foo2],
bar: %w[bar1 bar2]
)
end
当然,您也可以完全跳过该方法:
class User < ApplicationRecord
{
foo: %w[foo1 foo2],
bar: %w[bar1 bar2]
}.each do |key, values|
validates_presence_of key, in: values
end
end
如果您要编写一种使用其他验证的现有功能的验证方法,则可以创建ActiveRecord::Validator
或ActiveRecord::EachValidator
子类并在此处使用现有的验证。但是,您确实需要从reading the guides和API文档开始,以便对它的工作原理有基本的了解。