acts_as_tree不会破坏模型的子项

时间:2008-10-05 05:08:51

标签: ruby-on-rails ruby acts-as-tree

我有这个任务模型:

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|块时,测试会再次传递。

有什么想法吗?

2 个答案:

答案 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错误,它会告诉你发生了什么