![](/img/trans.png)
[英]Rails Rspec - model attribute undefined method `>' for nil:NilClass
[英]Rails model attribute is nil in custom validator method
我有一個多態表,我希望能夠驗證創建時提供的實體 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_type
和entity_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
可能是EntityOne
或EntityTwo
兩個模型中的任何一個。 您可以輕松地檢查其中任何一個是否包含有問題的 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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.