Mit dem Stil Rails 3 würde ich das Gegenteil von schreiben:
Foo.includes(:bar).where(:bars=>{:id=>nil})
Ich möchte herausfinden, wo id NICHT gleich null ist. Ich habe es versucht:
Foo.includes(:bar).where(:bars=>{:id=>!nil}).to_sql
Aber das kehrt zurück:
=> "SELECT \"foos\".* FROM \"foos\" WHERE (\"bars\".\"id\" = 1)"
Das ist definitiv nicht das, was ich brauche und scheint fast ein Fehler in ARel zu sein.
Der kanonische Weg dies mit Rails 3 zu tun:
Foo.includes(:bar).where("bars.id IS NOT NULL")
ActiveRecord 4.0 und höher fügt where.not
so kannst du das machen:
Foo.includes(:bar).where.not('bars.id' => nil)
Foo.includes(:bar).where.not(bars: { id: nil })
Bei der Arbeit mit Bereichen zwischen Tabellen bevorzuge ich die Verwendung von merge
, um die Verwendung vorhandener Bereiche zu vereinfachen.
Foo.includes(:bar).merge(Bar.where.not(id: nil))
Da includes
nicht immer eine Verknüpfungsstrategie auswählt, sollten Sie auch hier references
verwenden, da Sie sonst möglicherweise eine haben ungültiges SQL.
Foo.includes(:bar)
.references(:bar)
.merge(Bar.where.not(id: nil))
Es ist kein Fehler in ARel, es ist ein Fehler in Ihrer Logik.
Was Sie hier wollen, ist:
Foo.includes(:bar).where(Bar.arel_table[:id].not_eq(nil))
Für Rails4:
Also, was Sie wollen, ist ein innerer Join, also sollten Sie wirklich nur das Joins-Prädikat verwenden:
Foo.joins(:bar)
Select * from Foo Inner Join Bars ...
Wenn Sie jedoch die Bedingung "NOT NULL" haben möchten, verwenden Sie einfach das Prädikat "not":
Foo.includes(:bar).where.not(bars: {id: nil})
Select * from Foo Left Outer Join Bars on .. WHERE bars.id IS NOT NULL
Beachten Sie, dass in dieser Syntax eine Veraltetheit gemeldet wird (es handelt sich um ein SQL-Codefragment für Zeichenfolgen, aber ich vermute, die Hash-Bedingung wird im Parser in Zeichenfolge geändert?). Fügen Sie daher die Verweise am Ende hinzu:
Foo.includes(:bar).where.not(bars: {id: nil}).references(:bar)
ABWEICHUNGSWARNUNG: Es sieht so aus, als ob Sie eifrig Tabellen laden (eine von: ....), auf die in einem String-SQL-Snippet verwiesen wird. Zum Beispiel:
Post.includes(:comments).where("comments.title = 'foo'")
Derzeit erkennt Active Record die Tabelle in der Zeichenfolge und kann die Kommentartabelle mit der Abfrage verknüpfen, anstatt Kommentare in eine separate Abfrage zu laden. Dies zu tun, ohne einen vollständigen SQL-Parser zu schreiben, ist jedoch von Natur aus fehlerhaft. Da wir keinen SQL-Parser schreiben möchten, entfernen wir diese Funktionalität. Von nun an müssen Sie Active Record explizit mitteilen, wenn Sie eine Tabelle anhand einer Zeichenfolge referenzieren:
Post.includes(:comments).where("comments.title = 'foo'").references(:comments)
Ich bin mir nicht sicher, ob dies hilfreich ist, aber das hat bei mir in Rails 4 funktioniert
Foo.where.not(bar: nil)
Mit Rails 4 ist es einfach:
Foo.includes(:bar).where.not(bars: {id: nil})
Siehe auch: http://guides.rubyonrails.org/active_record_querying.html#not-conditions