我想我在这里很密集,因为我不断收到stack too deep
错误......
我有一个Child
和一个Parent
关系对象。我想要做两件事:
Child
,则无法将其status_id
更新为1
,除非它具有Parent
关联Parent
然后将其附加到Child
,则Child
的状态应自动设置为1
。 以下是Parent
关联的添加方式:
parent = Parent.new
if parent.save
child.update_attributes(parent_id:1)
end
我在Child
模型上有这些回调:
validate :mark_complete
after_update :set_complete
# this callback is here because there is a way to update the Child model attributes
def mark_complete
if self.status_id == 1 && self.parent.blank?
errors[:base] << ""
end
end
def set_complete
if self.logistic.present?
self.update_attribute(:status_id, 1)
end
end
上面的代码实际上并不那么有效,因为它理想情况下它会是1分贝命中,一次完成。但是我发现它太过于脑力不足以弄清楚为什么......我不确定为什么它甚至不能正常工作,因此甚至无法开始考虑使这成为一个单一的数据库事务。
示例
希望这有助于澄清。想象一下Charge
模型和Item
模型。每个Item
都有一个Charge
。 Item
也有一个属性paid
。两件事:
如果您更新Item
,则在paid
与true
对象相关联之前,您无法将Item
更新为Charge
/ p>
如果您通过更新Charge
上的Item
属性将charge_id
对象与Item
相关联,那么代码可以节省您的时间并自动设置paid
为true
答案 0 :(得分:1)
我发现有很多让我感到困惑的事情,但在我看来,你在:set_complete
之后调用after_update并且在set_complete
内你正在更新属性,因此你似乎有一个永久循环。可能还有其他循环,我看不到,但那个循环对我来说很突出。
答案 1 :(得分:0)
避免像这样的循环递归情况的一种方法是提供标志作为参数(或其他),以阻止循环继续。
在这种情况下,(虽然我完全不确定这个案例)我认为你可以提供一个标志来表明通话的来源。如果更新的来源是附加的费用,则传递一个标志,该标志将停止检查发生或修改它以防止发生循环。对于这种情况,也许是第二组逻辑?
答案 2 :(得分:0)
在使用ActiveRecord回调时,我在一段时间内遇到了stack level too deep
问题。
在我的情况下,问题出现在update_attribute
更新通过回调后,即在您的情况下再次调用set_complete
,其中update_attribute
将再次被触发,并且这将无休止地重复。 / p>
我通过使用update_column
而不是触发任何回调或验证来解决这个问题,但设置标志是更经常在线建议的。
此时我没有减少数据库写入操作的答案,如果我能想到任何事情,我会添加这个答案。
希望这有帮助