2008-10-05 3 views
5

ich diese Aufgabe Modell haben:acts_as_tree nicht die Kinder Modell zerstören

class Task < ActiveRecord::Base 
    acts_as_tree :order => 'sort_order' 
end 

Und ich habe diesen Test

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 

Der Test ist erfolgreich: Wenn ich d1 zerstören, es zerstört alle Nachkommen von d1. Somit ist nach der Zerstörung nur noch die Wurzel übrig.

Dieser Test schlägt jedoch fehl, nachdem ich der Task einen Rückruf vor_save hinzugefügt habe. Dies ist der Code, den ich zu Aufgabe hinzugefügt:

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 

Wenn ich diesen Code hinzugefügt, assert_equal 1, Task.count fehlschlägt, mit Task.count == 4. Ich denke self.children unter handled_parent_id_change ist der Täter, denn wenn ich den self.children.each do |sub_task| Block auskommentiere, geht der Test wieder durch.

Irgendwelche Ideen?

Antwort

4

Ich fand den Fehler. Die Zeile

d1 = create_task(:parent_id => @root.id, :sort_order => 2) 

erstellt d1. Dies ruft den Callback before_save auf, der wiederum self.children aufruft. Wie Orion bemerkte, werden die Kinder von d1 zwischengespeichert.

An diesem Punkt hat d1 jedoch noch keine Kinder. Der Cache von d1 ist also leer.

Also, wenn ich versuche, d1 zu zerstören, versucht das Programm, d1 Kinder zu zerstören. Es findet den Cache, findet, dass es leer ist, und ein Ergebnis zerstört nicht d2, d3 und d4.

Ich löste dies durch die Aufgabe Kreationen wie folgt zu ändern:

@root.children << (d1 = new_task(:sort_order => 2)) 
@root.save! 

Das so arbeitete ich bin in Ordnung mit ihm :) Ich denke, dass es auch möglich ist, dies entweder durch Neuladen d1 zu fixieren (d1.reload) oder self.children (self.children(true)) obwohl ich keine dieser Lösungen probiert habe.

1

childrenis a simple has_many association

Das bedeutet, wenn Sie .children nennen, wird es aus der Datenbank (falls nicht bereits vorhanden) geladen werden. Es wird sie dann zwischenspeichern.

Ich würde sagen, dass Ihr zweiter "Test" tatsächlich die zwischengespeicherten Werte nicht die reale Datenbank betrachten wird, aber das sollte nicht passieren, da Sie nur Task.count statt d1.children.count verwenden. Hrm

Haben Sie sich die Protokolle angesehen? Sie zeigen Ihnen die SQL, die ausgeführt wird. Sie können einen mysql Fehler darin sehen, der Ihnen sagt, was weitergeht

Verwandte Themen