gsm*_*oza 5 ruby ruby-on-rails acts-as-tree
我有这个任务模型:
class Task < ActiveRecord::Base
acts_as_tree :order => 'sort_order'
end
Run Code Online (Sandbox Code Playgroud)
我有这个测试
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
Run Code Online (Sandbox Code Playgroud)
测试成功:当我销毁d1时,它会破坏d1的所有后代.因此,在破坏之后只剩下根.
但是,在我向Task添加了before_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
Run Code Online (Sandbox Code Playgroud)
当我添加此代码时,assert_equal 1, Task.count
失败,用Task.count == 4
.我认为self.children
下面handled_parent_id_change
是罪魁祸首,因为当我注释掉该self.children.each do |sub_task|
块时,测试再次通过.
有任何想法吗?
我发现了这个错误。线路
d1 = create_task(:parent_id => @root.id, :sort_order => 2)
Run Code Online (Sandbox Code Playgroud)
创建 d1。这会调用before_save
回调,回调又会调用self.children
. 正如 Orion 指出的,这会缓存 d1 的子级。
然而,此时 d1 还没有任何子级。所以 d1 的子级缓存是空的。
因此,当我尝试销毁 d1 时,程序会尝试销毁 d1 的子级。它遇到缓存,发现它是空的,结果并没有破坏d2、d3和d4。
我通过更改任务创建解决了这个问题,如下所示:
@root.children << (d1 = new_task(:sort_order => 2))
@root.save!
Run Code Online (Sandbox Code Playgroud)
这很有效,所以我对此很满意:)我认为也可以通过重新加载 d1 ( d1.reload
) 或 self.children ( self.children(true)
) 来解决这个问题,尽管我没有尝试任何这些解决方案。