简体   繁体   English

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

[英]Rails model attribute is nil in custom validator method

I have a polymorphic table, and I want to be able to verify that the entity id provided on create does in fact reference an existing object.我有一个多态表,我希望能够验证创建时提供的实体 id 确实引用了现有对象。 I wrote a custom validator to do just this, which is invoked when I call find_or_create_by .我编写了一个自定义验证器来执行此操作,当我调用find_or_create_by时会调用它。 However, the attributes that I am performing validation on are nil in the validation method.但是,我正在对其执行验证的属性在验证方法中为零。

  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_type and entity_id are both model members, and are passed as args to find_or_create_by . entity_typeentity_id都是模型成员,并作为参数传递给find_or_create_by I don't understand why they are nil in the validation method.我不明白为什么它们在验证方法中为零。

The reason those values don't hold anything in your method is because they are only scoped to that method, and that method does not take them in as arguments.这些值在您的方法中不包含任何内容的原因是因为它们仅适用于该方法,并且该方法不会将它们作为参数。 The best way to accomplish what you're trying to do is to write a proper custom validator that inherits from ActiveModel::EachValidator and implements the validate_each(record, attribute, value) method.完成您要做的事情的最佳方法是编写一个适当的自定义验证器,该验证器继承自ActiveModel::EachValidator并实现validate_each(record, attribute, value)方法。

Although you can get away with a validates_each block:尽管您可以摆脱validates_each块:

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

However...然而...

Why not just use a normal inclusion validator?为什么不直接使用普通的包含验证器?
Since I'm on Rails 4.2 right now this is how I do it when Entity record counts are low enough for it not to cause performance issues.因为我现在在 Rails 4.2 上,所以当Entity记录数足够低以至于不会导致性能问题时,我就是这样做的。
(I'd use a better error message, but using yours for simplicity.) (我会使用更好的错误消息,但为了简单起见使用你的。)

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

Edit: I see now the issue is that your polymorphic entity means the examples above won't work without some tweaking since Entity could be either of two models EntityOne or EntityTwo .编辑:我现在看到的问题是您的多态实体意味着上面的示例在没有一些调整的情况下将无法工作,因为Entity可能是EntityOneEntityTwo两个模型中的任何一个。 You could easily check if either of them contain the ID in question like this:您可以轻松地检查其中任何一个是否包含有问题的 ID,如下所示:

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

Or或者

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

But this isn't a great validation since there are invalid situations passed through as valid.但这不是一个很好的验证,因为有无效的情况作为有效传递。

You might have to resort to a proper custom validator that inherits from ActiveModel::Validator and implements the validate(record) method which also accepts options where you can pass in the type of entity expected.您可能不得不求助于从ActiveModel::Validator继承并实现validate(record)方法的适当自定义验证器,该方法还接受您可以传入预期实体类型的options It would look like this:它看起来像这样:

# 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM