是否有可用于所有关联记录的特定属性的验证?

Is there a validation I can use for a specific attribute on all associated records?

我有一个 Question has_many :answers(就像 SO)。我还希望每个问题只有 1 个 accepted_answer,所以我只是向 Answer 模型添加了一个 :accepted 属性,它只是一个布尔值。

现在,为了让我的问题得到公认的答案,我在我的模型上编写了一个方法来执行此操作:

  def accepted_answer
    answers.where(accepted: true)
  end

这让我可以做 question.accepted_answer 并且它 returns 一个 ActiveRelation 对象,就像你期望的那样。

没什么特别的。简单有效。

但是,我想确保的是,在任何时刻,每个问题都只能有一个 accepted: true 的答案。

解决这个问题的最佳方法是什么?

我考虑过使用验证器,但找不到以这种方式处理关联对象的验证器。有些有一些有趣的点点滴滴,但我不能把所有的部分都放在一起。比如presence is interesting as is absence and validates_with(不过最后这个感觉太重了)

建议?

最好的方法很可能是使用 after_add 回调(例如 here),这将通过 update_all 将所有现有的 accepted 记录设置为 false以及接受设置为 true 的最新答案。这完全取决于你的逻辑。

您还可以使用一些其他回调,例如 before_save、before_update 等具有类似功能的回调,具体取决于您的应用程序细节。

它不会退出验证,但会有效地维护您的模型所需的状态。此外,验证的目的是在某些内容无效时向您发出警告,但我猜您想在没有此类失败的情况下保存您的对象,并且只执行一个接受的答案。

如果您想在第一个答案被接受后停止添加答案,请告诉我。在这种情况下,它需要不同的功能。