在自定义验证器方法中,Rails模型属性为nil



我有一个多态表,我希望能够验证create上提供的实体id是否引用了现有对象。为此,我编写了一个自定义验证器,当我调用find_or_create_by时会调用它。但是,在验证方法中,我正在执行验证的属性为零。

validate :validate_id, on: :create
...
def validate_id
klass = Object.const_get(entity_type)
return if klass.exists?(entity_id)
errors.add(:entity_id, 'is invalid')
end

entity_typeentity_id都是模型成员,并作为参数传递给find_or_create_by。我不明白为什么在验证方法中它们为零。

这些值在方法中不包含任何内容的原因是,它们的作用域仅限于该方法,而该方法不将它们作为参数。实现您尝试做的事情的最佳方法是编写一个适当的自定义验证器,该验证器继承自ActiveModel::EachValidator并实现validate_each(record, attribute, value)方法。

虽然你可以逃脱validates_each块:

validates_each :entity_id do |record, attr, value|
return if Entity.exists?(value)
errors.add(attr, 'is invalid')
end

然而。。。

为什么不使用普通的包含验证器呢
由于我现在使用的是Rails 4.2,所以当Entity记录计数足够低,不会导致性能问题时,我就是这样做的
(我会使用更好的错误消息,但为了简单起见,请使用您的错误消息。)

validates :entity_id,
inclusion: { in:      proc { Entity.all.pluck(:id) },
message: 'is invalid' }

编辑:我现在看到的问题是,你的多态实体意味着如果不进行一些调整,上面的例子就无法工作,因为Entity可以是EntityOneEntityTwo两个模型中的任何一个。你可以很容易地检查它们中是否有这样的ID:

validates_each :entity_id do |record, attr, value|
return if EntityOne.exists?(value) || EntityTwo.exists?(value)
errors.add(attr, 'is invalid')
end

validates :entity_id,
inclusion: { in:      proc { EntityOne.all.pluck(:id) + EntityTwo.all.pluck(:id) },
message: 'is invalid' }

但这并不是一个很好的验证,因为有些无效的情况会被视为有效。

您可能必须求助于一个适当的自定义验证器,该验证器继承自ActiveModel::Validator并实现validate(record)方法,该方法也接受options,您可以在其中传递所需的实体类型。它看起来是这样的:

# Inside the model:
validates_with(EntityIdValidator, expected_entity: entity_type)

#The custom validator:
class EntityIdValidator < ActiveModel::Validator
def validate(record)
expected_entity = options[:expected_entity]
return if expected_entity.exists?(record.entity_id)
record.errors.add(:entity_id, 'is invalid')
end
end

相关内容

  • 没有找到相关文章

最新更新