398 Stimmen

Rails where-Bedingung mit NOT NIL

Wie würde ich das Gegenteil von "rails 3" schreiben, wenn ich den Stil von rails 3 verwende?

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.

567voto

Adam Lassek Punkte 34556

Schiene 4+

ActiveRecord 4.0 und höher fügt hinzu where.not damit Sie dies tun können:

Foo.includes(:bar).where.not('bars.id' => nil)
Foo.includes(:bar).where.not(bars: { id: nil })

Bei der Arbeit mit Geltungsbereichen zwischen Tabellen bevorzuge ich die Verwendung von merge damit ich vorhandene Bereiche leichter nutzen kann.

Foo.includes(:bar).merge(Bar.where.not(id: nil))

Außerdem, da includes nicht immer eine Join-Strategie wählt, sollten Sie die references auch hier, da Sie sonst möglicherweise ungültiges SQL erhalten.

Foo.includes(:bar)
   .references(:bar)
   .merge(Bar.where.not(id: nil))

Schiene 3

Der kanonische Weg, dies mit Rails 3 zu tun:

Foo.includes(:bar).where("bars.id IS NOT NULL")

255voto

Ryan Bigg Punkte 104835

Es ist kein Fehler in ARel, sondern ein Fehler in Ihrer Logik.

Was Sie hier wollen, ist:

Foo.includes(:bar).where(Bar.arel_table[:id].not_eq(nil))

48voto

Raed Tulefat Punkte 621

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

Foo.where.not(bar: nil)

38voto

Matt Rogish Punkte 23629

Für Rails4:

Was Sie also wollen, ist eine innere Verknüpfung, also sollten Sie wirklich nur das Prädikat joins verwenden:

  Foo.joins(:bar)

  Select * from Foo Inner Join Bars ...

Aber, für das Protokoll, wenn Sie eine "NOT NULL"-Bedingung wollen, verwenden Sie einfach das not-Prädikat:

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 diese Syntax eine Verwerfung meldet (sie spricht von einem String-SQL-Snippet, aber ich vermute, dass die Hash-Bedingung im Parser in String geändert wird), also achten Sie darauf, die Referenzen am Ende hinzuzufügen:

Foo.includes(:bar).where.not(bars: {id: nil}).references(:bar)

DEPRECATION WARNING: Es sieht so aus, als würden Sie eifrig Tabelle(n) laden (eine von: ....), auf die in einem String-SQL-Snippet verwiesen wird. Zum Beispiel:

Post.includes(:comments).where("comments.title = 'foo'")

Zurzeit erkennt Active Record die Tabelle in der Stri die Kommentartabelle mit der Abfrage zu JOINen, anstatt die Kommentare in einer separaten Abfrage zu laden. Allerdings ist dies ohne das Schreiben eines vollwertigen SQL-Parser zu schreiben, ist von Natur aus mangelhaft. Da wir keinen SQL-Parser schreiben wollen Parser schreiben wollen, entfernen wir diese Funktionalität. Von nun an müssen Sie Active Record explizit mitteilen, wenn Sie eine Tabelle aus einer Zeichenfolge verweisen:

Post.includes(:comments).where("comments.title = 'foo'").references(:comments)

23voto

Tilo Punkte 32417

Mit Rails 4 ist das ganz einfach:

 Foo.includes(:bar).where.not(bars: {id: nil})

S http://guides.rubyonrails.org/active_record_querying.html#not-conditions

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X