我有这个任务模型:
class Task < ActiveRecord::Base
acts_as_tree :order => 'sort_order'
end
我有这个测试
class TaskTest < Test::Unit::TestCase
def setup
@root = create_root
end
def test_destroying_a_task_should_destroy_all_of_its_descendants
d1 = create_task(:parent_id => @root.id, :sort_order => 2)
d2 = create_task(:parent_id => d1.id, :sort_order => 3)
d3 = create_task(:parent_id => d2.id, :sort_order => 4)
d4 = create_task(:parent_id => d1.id, :sort_order => 5)
assert_equal 5, Task.count
d1.destroy
assert_equal @root, Task.find(:first)
assert_equal 1, Task.count
end
end
测试成功:当我销毁d1时,它会破坏d1的所有后代。因此,在毁灭之后只剩下根。
但是,在我将task_save回调添加到Task之后,此测试现在失败了。这是我添加到任务中的代码:
before_save :update_descendants_if_necessary
def update_descendants_if_necessary
handle_parent_id_change if self.parent_id_changed?
return true
end
def handle_parent_id_change
self.children.each do |sub_task|
#the code within the loop is deliberately commented out
end
end
当我添加此代码时,assert_equal 1, Task.count
失败,Task.count == 4
。我认为self.children
下的handled_parent_id_change
是罪魁祸首,因为当我注释掉self.children.each do |sub_task|
块时,测试会再次传递。
有什么想法吗?
答案 0 :(得分:4)
我发现了这个错误。这条线
d1 = create_task(:parent_id => @root.id, :sort_order => 2)
创建d1。这会调用before_save
回调,后者又调用self.children
。正如猎户座所指出的,这会缓解d1的孩子们。
然而,此时,d1还没有任何孩子。所以d1的孩子们的空白是空的。
因此,当我试图摧毁d1时,程序试图摧毁d1的孩子。它遇到缓存,发现它是空的,结果不会破坏d2,d3和d4。
我通过改变这样的任务创作解决了这个问题:
@root.children << (d1 = new_task(:sort_order => 2))
@root.save!
这样就可以了,我很好用:)我认为也可以通过重新加载d1(d1.reload
)或self.children(self.children(true)
来解决这个问题,尽管我没有尝试任何这些解决方案。
答案 1 :(得分:1)
children
is a simple has_many association
这意味着,当您调用.children
时,它将从数据库中加载它们(如果尚未存在)。然后它会缓存它们。
我打算说你的第二个'测试'实际上是在查看缓存的值而不是真正的数据库,但这不应该发生,因为你只是使用Task.count
而不是d1.children.count
。 HRM
你看过日志了吗?他们将向您显示正在执行的SQL。你可能会在那里看到一个mysql错误,它会告诉你发生了什么