Mit arel
kann dich ziemlich weit bringen. Der knifflige Teil ist, wie Sie nicht Ihre gesamte Abfrage mit arel
schreiben 's eigene Abfragesyntax?
Hier ist ein Trick:Wenn Sie Ihre Abfrage mit where
erstellen , wenn Sie arel
verwenden Bedingungen erhalten Sie einige zusätzliche Methoden kostenlos. Beispielsweise können Sie die Unterabfrage, die Sie dort haben, mit .exists.not
abschließen , wodurch Sie einen (NOT ( EXISTS (subquery)))
erhalten Werfen Sie das in das where
der Eltern -Klausel und fertig.
Die Frage ist, wie verweisen Sie auf die beteiligten Tabellen? Dafür brauchst du Arel. Sie könnten Verwenden Sie Arels where
mit seinen hässlichen Bedingungen wie a.eq b
. Aber wieso? Da es sich um eine Gleichheitsbedingung handelt, können Sie stattdessen die Bedingungen von Rails verwenden! Sie können auf die abgefragte Tabelle mit einem Hash-Schlüssel verweisen, aber für die andere Tabelle (in der äußeren Abfrage) können Sie deren arel_table
verwenden . Sehen Sie sich das an:
parents = Parent.arel_table
Parent.where(
Child.where(other_parent_id: nil, parent_id: parents[:id]).exists.not
)
Sie können die Nutzung von Arel sogar reduzieren, indem Sie ein wenig auf Strings zurückgreifen und sich darauf verlassen, dass Sie Unterabfragen als Parameter in Rails' where
einspeisen können . Es hat nicht viel Nutzen, aber es zwingt Sie nicht, sich zu sehr mit Arels Methoden zu beschäftigen, also können Sie diesen Trick oder andere SQL-Operatoren verwenden, die eine Unterabfrage verwenden (gibt es überhaupt andere?):
parents = Parent.arel_table
Parent.where('NOT EXISTS (?)',
Child.where(parent_id: parents[:id], other_parent_id: nil)
)
Die zwei Hauptpunkte hier sind:
- Sie können Unterabfragen genauso erstellen, wie Sie es gewohnt sind, reguläre Abfragen zu erstellen, indem Sie mit Arel auf die Tabelle der äußeren Abfrage verweisen. Es kann nicht einmal ein echter Tisch sein, es kann ein Alias sein! Verrücktes Zeug.
- Sie können Unterabfragen als Parameter für
where
von Rails verwenden Methode ganz gut.