Ich bin ein PHP-Entwickler, der die Faszination von Ruby on Rails lernt. Ich liebe ActiveRecord und habe etwas wirklich Interessantes bemerkt. So erkennen ActiveRecord-Methoden das Ende der Methodenkette, um die Abfrage auszuführen.
@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?
x = Person.where(..); @person = x.where(..)
, was identisch funktionieren soll. Es macht es einige Zeit später, also was ist der Auslöser? ;-)Antworten:
Die
where
Methode gibt einActiveRecord::Relation
Objekt zurück, und dieses Objekt gibt selbst keine Datenbankabfrage aus. Hier kommt es darauf an, wo Sie dieses Objekt verwenden.In der Konsole machen Sie wahrscheinlich Folgendes:
@person = Person.where(name: "Jason")
Und dann gibt blammo eine Datenbankabfrage aus und gibt ein Array von allen mit dem Namen Jason zurück. Ja, aktiver Rekord!
Aber dann machst du so etwas:
@person = Person.where(name: "Jason").where(age: 26)
Und dann gibt das eine andere Abfrage aus, aber diese ist für Leute, die Jason heißen und 26 Jahre alt sind. Aber es gibt nur eine Abfrage, also wohin ging die andere Abfrage?
Wie andere vorgeschlagen haben, geschieht dies, weil die
where
Methode ein Proxy-Objekt zurückgibt. Es führt keine Abfrage durch und gibt ein Dataset zurück, es sei denn, es wird dazu aufgefordert.Wenn Sie etwas in der Konsole ausführen , wird die überprüfte Version des Ergebnisses dessen ausgegeben, was auch immer Sie ausgeführt haben. Wenn Sie setzen
1
in der Konsole und drücken Sie die Eingabetaste, erhalten Sie1
zurück , weil1.inspect
ist1
. Magie! Gleiches gilt für"1"
. Eine Vielzahl anderer Objekte nicht über eineinspect
Methode definiert und so Ruby des auf zurückfälltObject
das wieder etwas grässlich wie<Object#23adbf42560>
.Auf jedem einzelnen
ActiveRecord::Relation
Objekt ist dieinspect
Methode definiert, sodass eine Abfrage ausgelöst wird. Wenn Sie die Abfrage in Ihre Konsole schreiben, ruft IRBinspect
den Rückgabewert dieser Abfrage auf und gibt etwas aus, das fast für Menschen lesbar ist, wie das Array, das Sie sehen würden.Wenn Sie dies nur in einem Standard-Ruby-Skript ausgeben, wird keine Abfrage ausgeführt, bis das Objekt (via
inspect
) inspiziert oder durch using iterierteach
wurde oder dieto_a
Methode aufgerufen wurde.Bis eines dieser drei Dinge passieren, können Sie Kette als viele
where
Erklärungen, wie Sie mögen und dann , wenn Sie tun Anrufinspect
,to_a
odereach
auf sie, dann wird es schließlich die Abfrage auszuführen.quelle
Es gibt eine Reihe von Methoden, die als "Kicker" bezeichnet werden und die Abfrage an die Datenbank tatsächlich auslösen. Zuvor erstellen sie lediglich AST-Knoten, die nach dem Kick das eigentliche SQL (oder die Sprache, in die kompiliert wird) generieren und die Abfrage ausführen.
In diesem Blog-Beitrag finden Sie eine ausführlichere Erklärung dazu.
quelle
Sie können den Code lesen, aber ein Konzept hier ist das Proxy-Muster.
Wahrscheinlich ist @person nicht das eigentliche Objekt, sondern ein Proxy für dieses Objekt. Wenn Sie dort ein Attribut benötigen, führt der aktive Datensatz die Abfrage schließlich aus. Der Ruhezustand hat das gleiche Konzept.
quelle
Vielleicht etwas zu spät, aber Sie können einen Hash verwenden:
@person = Person.where({name: "Jason", age: 26})
Resultierende Abfrage:
SELECT "person".* FROM "person" WHERE "person"."name" = 'Jason' AND "person"."age" = 26
quelle