我有一个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
我不确定我是否完全理解您的问题,但是这部分代码存在一个问题:
validates :company_id, inclusion: {in: Company.pluck(:id).prepend(nil)}
验证是在类级别配置的,因此它不能很好地与该模型上的更新配合使用(不会在后续验证中重新评估)。
文档指出您可以使用块进行包含,因此您也可以尝试这样做:
validates :company_id, inclusion: {in: proc { Company.pluck(:id).prepend(nil) }}
有些人会建议您甚至不要执行此验证,而是对该列进行数据库约束。
我相信你在这里滥用了包含验证器。如果要验证关联的模型是否存在,而不是其 id 列是否具有值,可以通过两种方式执行此操作。在 ActivRecord 中,您可以使用状态验证器。
validates :company, presence: true
还应在数据库级别使用外键约束。这样可以防止在关联表中没有相应记录时保存模型。
add_foreign_key :雇主, :公司
如果它通过 ActiveRecord,如果没有具有给定company_id
的公司记录,数据库将引发错误。