我有Company
模型和Employer
模型。 Employer
belongs_to :company
和Company
has_many :employers
。在我的Employer
模型中,我有以下验证:
validates :company_id, inclusion: {in: Company.pluck(:id).prepend(nil)}
我遇到了上述验证失败的问题。以下是控制器操作中的示例设置,该操作将导致验证失败:
company = Company.new(company_params)
# company_params contains nested attributes for employers
company.employers.each do |employer|
employer.password = SecureRandom.hex
end
company.employers.first.role = 'Admin' if client.employers.count == 1
company.save!
admin = company.employers.where(role: 'Admin').order(created_at: :asc).last
admin.update(some_attr: 'some_val')
在示例代码段的最后一行,admin.update
将失败,因为验证正在检查列表中是否包含company_id
,因为列表是在之前生成的company
已保存。
显然有很多方法可以解决这个问题,比如抓住我是什么我想知道是否有更好的方法来解决这个问题。company.id
的值,然后再用它来定义admin
,但这似乎是一个迂回的解决方案。
更新
显然我建议的可行解决办法甚至不起作用。
new_company = Company.find(company.id)
admin = new_company.employers.where(role: 'Admin').order(created_at: :asc).last
admin.update
# Fails validation as before
答案 0 :(得分:2)
我不确定我是否完全理解您的问题,但您的代码中存在明显的缺陷
validates :company_id, inclusion: {in: Company.pluck(:id).prepend(nil)}
验证是在类级别配置的,因此它不能很好地处理该模型的更新(不会在后续验证中重新评估)。
文档说明你可以使用一个块来包含,所以你也可以尝试这样做:
validates :company_id, inclusion: {in: ->() { Company.pluck(:id).prepend(nil) }}
从我的角度来看,你甚至不应该进行这种验证,但是没有该列的数据库约束。
答案 1 :(得分:0)
我相信你在这里滥用了包含验证器。如果要验证关联模型是否存在,而不是其id列具有值,则可以通过两种方式执行此操作。在ActivRecord中,您可以使用presence validator。
validates :company, presence: true
您还应该在数据库级别使用foreign key constraint。如果关联表中没有相应的记录,这可以防止保存模型。
add_foreign_key:雇主,:公司
如果它超过ActiveRecord,如果没有给定company_id
的公司记录,数据库将抛出错误。