2015-12-27 7 views
8

Meine Elternklasse lädt manchmal nicht alle ihre untergeordneten Elemente in einem after_save Rückruf durch das Kind.Rails-Verbindung wird nicht korrekt geladen

Ich habe zwei Modelle:

class Parent < ActiveRecord::Base 
    has_many :children 

    def update_something 
    # explained below 
    end 
end 

class Child < ActiveRecord::Base 
    belongs_to :parent 

    after_save :tell_parent_to_update 

    def tell_parent_to_update 
    parent.update_something 
    end 
end 

ich einen Test habe ich darauf laufen, die zwei Dinge einfach überprüft. parent.children.count und parent.children.length. Beides sollte 4 sein. Mir ist klar, dass die Anzahl manchmal anders ist, aber (so weit ich weiß) sollte es nicht hier sein.

Wenn ich update_something definieren, um nur iterieren children:

def update_something 
    children.each do |child| 
    end 
end 

der Test nicht bestanden - die Schleife einmal ausgeführt wird (und wird das Feld von einem einzigen Kind zurückgeben - die erstenchild erstellt) .

Ansonsten kann ich jeden Code setzen, solange es children nicht erwähnt und es wird funktionieren. Es ist so, als ob der Anruf bei Kindern dazu führt, dass die Assoziation die falsche Sache lädt.

einen Reload Erzwingen behebt es:

def update_something 
    children(true).each do |child| 
    end 
end 

aber das ist Hacky und ich würde lieber die Wurzel Problem beheben, wenn möglich.

Ist das mein Bug oder ein Rails Bug (und wenn ja, kann ich etwas dagegen tun)?

Ich bezweifle, dass es darauf ankommt, aber dies ist eine Testumgebung mit sqlite3. Es wird jedoch auch in einer Entwicklungsumgebung fehlschlagen, wenn ich die Datensätze in einer einzigen Dev-Konsolensitzung erstelle und teste.

+0

'children.each do | child |' oder 'Children.each do | child |'? –

+0

vielleicht etwas mit Keywords zu tun, nur Raten. – Nithin

+0

Das dachte ich auch zuerst, aber im echten Code ist es jetzt sehr isoliert, und die eigentlichen Namen der Modelle/Methoden sind extrem domänenspezifisch und leider keine Schlüsselwörter –

Antwort

3

Stab im Dunkeln, aber Sie können inverse_of brauchen, die ich speichert die zugehörigen Objekte im selben Speicherblock glauben, wie ein Standard-Ansatz schaffen würde zu den verschiedenen Blöcken gegen:

#app/models/parent.rb 
class Parent < ActiveRecord::Base 
    has_many :children, inverse_of: :parent 
    ... 
end 

#app/models/child.rb 
class Child < ActiveRecord::Base 
    belongs_to :parent, inverse_of: :children 
    ... 
end 

In meinem eigenen Erfahrung, ich habe inverse_of gefunden können Sie die assoziativen Daten in den anderen Modellen aufrufen. Beispielsweise würde der Aufruf von parent.update_somethingohneinverse_of entweder zu einem Fehler führen (wenn parent nicht explizit definiert wurde) oder das Objekt parent erneut erstellen.

Es gibt eine good write-up here.

-

ich die Antwort löschen würde, wenn es nicht hilft.

+0

Leider schien es nicht zu beheben. Laut der Zuschreibung und was ich online gefunden habe, geht es ab Gleis 4.1 (ich bin 4.2) automatisch damit um. Es wäre nützlich, diese Antwort zu hinterlassen, für den Fall, dass es für jemanden in der Zukunft repariert wird. –

+0

In Ordnung, danke für das Heads-up. Ich überlasse es der Nachwelt! –

0

Dies ist wahrscheinlich, weil die Kinder des Elternteils an einem Punkt in Ihrem Code eifrig geladen werden, bevor tell_parent_to_update ausgeführt wird.

parent.children.count führt eine SQL-Abfrage aus und gibt die Anzahl der untergeordneten Elemente im DB zurück, während parent.children.length die Länge des untergeordneten Elements (das wahrscheinlich bereits geladen ist) zurückgibt.

Ich würde vorschlagen, Sie manuell versuchen, 1 Kinderobjekt von der Rails-Konsole zu speichern und sehen, ob die Länge und Anzahl der Kinder in update_something ist die gleiche. Wenn dies der Fall ist, wird Ihr Test wahrscheinlich aufgrund eines Codes fehlschlagen.