wake-up-neo.com

Rails where bedingung using NOT NIL

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.

351
SooDesuNe

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))
499
Adam Lassek

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))
251
Ryan Bigg

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)
36
Matt Rogish

Ich bin mir nicht sicher, ob dies hilfreich ist, aber das hat bei mir in Rails 4 funktioniert

Foo.where.not(bar: nil)
23
Raed Tulefat

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

21
Tilo