2009-09-03 4 views
38

Kann jemand herausfinden, ob eine Rails-Verbindung geladen wurde?Wie ermittelt man, ob die Rails-Assoziation geladen ist?

Meine Situation: Ich habe eine Ergebnismenge, wo manchmal eine der Vereinigungen eifrig geladen ist, und manchmal ist es nicht. Wenn es nicht eifrig geladen ist, dann möchte ich nach Verknüpfungen suchen, die den Fund von ActiveRecord verwenden. Wenn es eifrig geladen ist, möchte ich erkennen.

Zum Beispiel, sagen, dass ich eine „has_many“ Array von shipping_info Objekten in meinem Artikel Modell. Dann:

Wenn Artikel eifrig geladen ist, effizienteste Last ist:

item.shipping_infos.detect { |si| si.region == "United States" } 

Wenn Artikel nicht eifrig geladen ist, effizienteste Last:

item.shipping_infos.where(region: "United States").first 

Aber es sei denn, ich weiß, ob es ist eifrig geladen, ich weiß nicht, welchen Code zu rufen, um den Datensatz effizient zu bekommen. Wenn ich die erste Methode verwende, wenn sie nicht eifrig geladen wurde, dann muss ich mehr DB-Datensätze nachsehen als nötig. Und wenn ich die zweite Methode benutze, wenn sie geladen wurde, dann werden meine eifrig geladenen Objekte ignoriert.

Antwort

41

item.shipping_infos.loaded? wird Ihnen sagen.

Ich muss sagen, aber: Dieser Weg führt ... in den Wahnsinn vor Code schreiben, der loaded? zwischen #detect und #find, stellen Sie sicher, dass diese Instanz wirklich Angelegenheiten in Bezug auf alles, was vor sich geht, zu entscheiden, prüft.

Ist dies nicht der langsamste Sache ist Ihre Anwendung tut, das Hinzufügen von zusätzlichen Codepfade fügt unnötige Komplexität. Nur weil Sie vielleicht ein wenig Datenbankaufwand verschwenden, bedeutet das nicht, dass Sie es beheben müssen - es ist wahrscheinlich in keiner messbaren Weise von Bedeutung.

+0

Danke Bryan. Ich verstehe, woher du kommst. Dieser spezielle Code wird in unserer gesamten App am häufigsten als partiell bezeichnet, so dass das Abmellen selbst in Mikrosekunden einen messbaren Unterschied macht. Ich gebe #loaded? ein Versuch. – wbharding

+9

Dies funktioniert nur für has_many-Zuordnungen! Im Falle von orders_to wird dieser Aufruf tatsächlich das andere Objekt laden (so wird es immer wahr) – reto

2

Werfen Sie einen Blick auf die Bullet gem.. Dadurch erfahren Sie, wann Sie eifriges Laden verwenden sollten und sollten.

+0

Bullet hat sich als sehr nützlich erwiesen, obwohl ich noch sehr wenig andere DB-Optimierung gemacht habe. Zumindest werden einige unnötige Zeilen in der Konsolenausgabe entfernt. ;) – lime

+0

Bullet Plugin Link ist tot. –

3

Sie können feststellen, ob eine einzelne Verknüpfung mit loaded_ foo geladen wurde oder nicht. Wenn shipping_info beispielsweise eine assignes_to-Zuordnung ist, dann item.loaded_shipping_info? wird true zurückgeben, wenn es eifrig geladen wurde. Seltsamerweise scheint es, dass es nil (anstatt false) zurückgibt, wenn es nicht geladen wurde (in Rails 2.3.10 sowieso).

+3

Das wurde in Rails 3.1 entfernt: https://github.com/rails/rails/issues/472 – Forrest

2

Lösung für dieses Problem sollte foo.association(:bla).loaded? sein, aber es funktioniert nicht richtig - es überprüft und Marken Verein als schmutzig:

class Foo; has_one :bla, :autosave => true end 
foo.association(:bla).loaded? #=> false 
foo.save # saves foo and fires select * from bla 

Also habe ich folgende Erweiterung Active hinzugefügt:

module ActiveRecord 
    class Base 
    def association_loaded?(name) 
     association_instance_get(name).present? 
    end 
    end 
end 

und jetzt:

class Foo; has_one :bla, :autosave => true end 
foo.association_loaded?(:bla) #=> false 
foo.save # saves foo 
+0

Sie sollten überprüfen, dass dies immer noch ein Problem ist und die Antwort aktualisieren, um es auf die entsprechenden Rails-Versionen zu beschränken. Ich konnte mich nicht reproduzieren. –

+0

Immer noch ein Problem wie Rails 4.2.6. Nicht sicher, ob Rails 5 es hat. – Omnilord

+0

Was hat es zur Folge, dass es schmutzig ist? Nur eine zusätzliche Select-Anweisung? Oder gibt es mehr Schaden? – lulalala

19

Ich würde empfehlen item.association_ cache.keys, die eine Liste der geladenen geladenen Assoziationen bereitstellen. Also hast du item.association_cache.keys.include?: Name_der_Vereinigung

+1

Perfekte Lösung. Dabogert du bist der König :) – Benj

+0

Wow, kann nicht glauben, dass ich das vermisst habe. Dies funktioniert in Fällen, in denen die Verknüpfung NICHT geladen ist, aber ein Cache im Arbeitsspeicher vorhanden ist (z. B. wenn Sie ein Objekt mithilfe der Verknüpfung erstellen). –