2012-05-25 11 views
52

Ich bin ein PHP-Entwickler, der die Ehrfurcht von Ruby on Rails lernt, ich liebe ActiveRecord und ich habe etwas sehr Interessantes bemerkt. Auf diese Weise erkennen ActiveRecord-Methoden das Ende der Methodenkette, um die Abfrage auszuführen.Wie kettet Rails ActiveRecord "Where" -Klauseln ohne mehrere Abfragen?

@person = Person.where(name: 'Jason').where(age: 26) 

# In my humble imagination I'd think that each where() executes a database query 
# But in reality, it doesn't until the last method in the chain 

Wie funktioniert diese Zauberei?

+0

Es tut es nicht in der letzten Methode. Das kann man nicht wissen. Betrachte 'x = Person.where (..); @person = x.where (..) ', die identisch funktionieren sollte. Es macht es irgendwann später, also was ist der Auslöser? ;-) –

Antwort

122

Die Methode where gibt ein Objekt ActiveRecord::Relation zurück, und dieses Objekt gibt selbst keine Datenbankabfrage aus. Es ist wo Sie dieses Objekt verwenden, das zählt.

in der Konsole sind Sie wahrscheinlich dies zu tun:

@person = Person.where(name: "Jason") 

Und dann blammo es eine Datenbankabfrage ausgibt und zurückgibt, was eine Reihe von jeder zu sein scheint Jason genannt. Yay, aktive Aufzeichnung!

Aber dann tun Sie etwas wie folgt aus:

@person = Person.where(name: "Jason").where(age: 26) 

Und dann die andere Abfrage ausgibt, aber für Menschen ein, die Jason genannt werden, die 26 sind, aber es ist nur eine Abfrage ausgeben, also wo würde die andere Abfrage gehen?


Wie andere vorgeschlagen haben, dies geschieht, weil die where Methode einen Proxy-Objekt zurückgibt. Es führt keine Abfrage durch und gibt ein Dataset nur zurück, wenn es dazu aufgefordert wird.

Wenn Sie irgendetwas in der Konsole ausführen, wird es die überprüfte Version des Ergebnisses von was auch immer Sie ausgeführt wird, ausgeben. Wenn Sie 1 in die Konsole eingeben und die Eingabetaste drücken, erhalten Sie 1 zurück, da 1.inspect1 ist. Zauber! Gleiches gilt für "1". Eine Vielzahl von anderen Objets haben keine inspect Methode definiert und so Ruby fällt zurück auf die auf Object, die etwas zurückgibt ghastly wie <Object#23adbf42560>.

Jedes einzelne ActiveRecord::Relation Objekt hat die inspect Methode definiert, so dass es eine Abfrage verursacht. Wenn Sie die Abfrage in Ihre Konsole schreiben, ruft IRB inspect auf dem Rückgabewert von dieser Abfrage auf und gibt etwas fast menschenlesbares aus, wie das Array, das Sie sehen würden.


Wenn Sie diese in einem Standard-Ruby-Skript nur wurden die Ausgabe, dann würde keine Abfrage ausgeführt werden, bis das Objekt (via inspect) oder wurde durch den Einsatz von each iteriert, oder hatte die to_a Methode auf sie genannt wurde inspiziert.

Bis eines dieser drei Dinge passieren, können Sie Kette so viele where Aussagen auf, wie Sie mögen und dann, wenn Sie inspect Telefonieren, to_a oder each drauf, dann wird es schließlich die Abfrage auszuführen.

+1

Unterhaltsam und informativ! Vielen Dank! – henrebotha

+1

Relevante [Railscast] (http://railscasts.com/episodes/239-activerecord-relation-walkthrough) erklärt es mit dem Rails-Quellcode. – flexus

+0

Geist geblasen ...... – sixty4bit

4

Sie können den Code lesen, aber ein Konzept hier ist das Proxy-Muster.

Wahrscheinlich @person ist nicht das reale Objekt, sondern ein Proxy für dieses Objekt, und wenn Sie ein Attribut benötigen, führt der aktive Datensatz schließlich die Abfrage aus. Hibernate hat das gleiche Konzept.

6

Es gibt eine Reihe von Methoden, die als "Kicker" bekannt sind und die Abfrage tatsächlich an die Datenbank absetzen. Zuvor erstellen sie nur AST-Knoten, die, sobald sie einmal ausgelöst wurden, das eigentliche SQL (oder die Sprache, zu der kompiliert wird) generieren und die Abfrage ausführen.

Siehe this blog post für eine tiefere Erklärung, wie dies getan wird.

-1

Bit Vielleicht zu spät, aber sie einen Hash verwenden können:

@person = Person.where({name: "Jason", age: 26}) 

resultierende Abfrage:

SELECT "person".* FROM "person" WHERE "person"."name" = 'Jason' AND "person"."age" = 26 
Verwandte Themen