对于嵌套的父/子模型,Rails会以什么顺序进行模型回调?

我知道保存模型的一般顺序是最深的孩子,然后逐渐到达父母。 但我对其他回调感到疑惑,是否会发生以下情况:

ChildA - before validation ChildB - before validation Parent - before validation ChildA - after validation ChildB - after validation Parent - after validation ChildA - before save ChildB - before save Parent - before save ... 

或者沿着以下方向:

 ChildA - before validation ChildA - after validation ChildA - before save ... ChildB - before validation ChildB - after validation ChildB - before save ... Parent - before validation Parent - after validation Parent - before save ... 

这很重要的原因是我有调整属性的回调,并且模型上属性的可调整性取决于其他模型的属性。

一个例子是,如果ChildAchild B's状态attributes are both Complete and the children are both节点都是有效的,我希望Parent将其status属性自动设置为Complete

我尝试使用puts语句对此进行测试,但显然,这会导致一些奇怪的行为(请参阅此问题: 嵌套表单validation语句重复多次 ),我担心它不具代表性。

我肯定读过Rails指南,但也许我是盲目的,因为我没有看到任何地方的引用……

虽然将这种状态机逻辑放在回调中可能很诱人,但这使得难以理解的代码。 相反,请考虑使用专用方法以更直接的方式收集和更改数据。

这也有助于数据一致性和测试,如本博文中所述。

有趣的问题。 默认情况下,首先运行父级中定义的回调。 prepend: true选项允许您调整该行为。

请参阅Rails API中的 “排序回调”部分。 它还值得检查“可inheritance的回调队列”部分,因为重新定义方法与使用宏不同。

PS以上所述至少对4.2.5.2版本有效

通过试验rails,我遇到了父进行validation,然后是子进程,但没有rails核心成员对此发表了意见。

这就是为什么你可以将逻辑移动到父级:

 class Sale has_many :details before_validation :evaluate_details # validations def evaluate_details self.details.each do |detail| detail.generate_info detail.items.each do |item| item.dance end end end end class Detail belongs_to :sale has_many :items # validations def generate_info # Do things end end class Item belongs_to :detail # validations def dance # Dancing end end 

这可以防止多次执行并管理执行顺序。

PD:您也可以避免使用before_validation回调并手动调用该方法。