ActiveRecord 验证列表中包含的内容 - 创建新的关联模型后,列表不会更新



我有一个Company模型和一个Employer模型。 Employer belongs_to :companyCompany 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的公司记录,数据库将引发错误。

最新更新