ODER-operator in WHERE-Klausel mit Arel in Rails 4.2
Den folgenden code gebaut, eine gültige where
- Klausel mit einer OR
Betreiber in Rails 4.1
MyModel.where(
MyModel.where(attribute1: 1, attribute2: 2).where_values.reduce(:or)
)
Was in etwa äquivalent zu der SQL
select * from my_models where (attribute1 = 1 OR attribute2 = 2)
In Rails 4.2 der gleiche code generiert eine SQL-Abfrage mit fehlenden Werten für Sie die bind-Parameter
select * from my_models where attribute1 = OR attribute2 =
... und generiert eine Fehlermeldung wegen der fehlenden Werte für die gebundenen Werte.
Was ist der entsprechende code in Rails 4.2 zum generieren einer gültigen Abfrage mit einem or-operator?
Edit:
Die Lösung erfordert einen Arel::Nodes::Node
abgeleitetes Objekt verwendet werden, so dass es sich in Kombination mit anderen Bedingungen, die über und-UND ODER-Gruppierungen.
rel = MyModel.where(attribute1: 1, attribute2: 2)
conditions = [rel.where_values.reduce(:or).to_sql, *rel.bind_values.map(&:last)]
MyModel.where(conditions)
Den conditions
var muss ein Derivat von Arel::Nodes::Node
. Die obige Lösung funktioniert für einfache Abfragen, aber für kompliziertere Anfragen, conditions
muss eine Arel-Knoten übergeben werden, um eine endgültige Abfrage-Methode.
- where_values war entfernt von Rails 4.2 ... zumindest wenn ich nach den APIs, die ich finden es in 3.x, aber nicht in 4.2. Das kann gut die Ursache des Problems.
- where_values ist Teil der privaten API in Rails 4.2... es gibt Sie noch. Die bind-Werte sind in bind_values... auch privat. Die jüngsten änderungen Arel über AdequateRecord sind die Ursache für das Problem.
- Ok, gute Sache. War nicht 100% sicher, da war es "entfernt" von der öffentlichen API (daher die Bemerkung v. Antwort).
- Was bedeutet
Model.where(conditions).where_values.reduce(:or).to_sql
zurück? "(attribute1 = ? OR attribute2 = ?)"
- helfen
Du musst angemeldet sein, um einen Kommentar abzugeben.
Bin ich mit dem unten, bis die Schienen 5 raus ist (in rails 5 AR unterstützt
.or
):Mit der oben Sie tun können:
Mehr richtig-Lösung auf Basis von @bsd Antwort, aber erlauben beliebige Bereiche auf input
P. S. Vorherigen code von @bsd kann nicht richtig arbeiten in wenig schwierigen Fall:
Benutzer.wo.oder(für User.wo(Bewertung: 3), Benutzer.wo(startups: { progress: 100, rating: null })
Ergebnis der alte code ist falsch:
Geänderte code generieren korrigieren:
Verwenden des raw-arel eine bessere option sein könnte: