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

时间:2016-02-11 17:47:29

标签: ruby-on-rails validation 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

2 个答案:

答案 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的公司记录,数据库将抛出错误。