web-dev-qa-db-ja.com

NOT NILを使用した条件付きレール

Rails 3スタイルを使用して、私は反対のことをどのように書くでしょう:

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

Idがnil以外であるところを見つけたい。私は試した:

Foo.includes(:bar).where(:bars=>{:id=>!nil}).to_sql

しかし、それは戻ります:

=> "SELECT     \"foos\".* FROM       \"foos\"  WHERE  (\"bars\".\"id\" = 1)"

それは私が必要としていることとは違い、間違いなくARelのバグのように思えます。

348
SooDesuNe

Rails 3でこれを行うための標準的な方法:

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

ActiveRecord 4.0以降では where.not が追加されているので、これを実行できます。

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

テーブル間のスコープを扱うときは、既存のスコープをより簡単に使用できるように、 merge を利用することを好みます。

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

また、 includes は常に結合方法を選択するわけではないので、ここでも references を使用する必要があります。無効なSQLです。

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

これはARelのバグではなく、ロジックのバグです。

ここで欲しいのは:

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

Rails4の場合:

だから、あなたが欲しいのは内部結合です、それであなたは本当に結合述語を使うべきです:

  Foo.joins(:bar)

  Select * from Foo Inner Join Bars ...

しかし、レコードについては、 "NOT NULL"条件が必要な場合は単純にnot述語を使用します。

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

Select * from Foo Left Outer Join Bars on .. WHERE bars.id IS NOT NULL

この構文は非推奨を報告していることに注意してください(これは文字列のSQLスニペットについて話していますが、ハッシュ条件はパーサーではstringに変更されていると思いますか?)。

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

非推奨警告:文字列のSQLスニペットで参照されているテーブル(:....の1つ)をロードしようとしているようです。例えば:

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

現在、Active Recordは文字列内のテーブルを認識し、別のクエリでコメントを読み込むのではなく、コメントテーブルをクエリに結合することを認識しています。しかし、本格的なSQLパーサーを書かずにこれを行うことは本質的に欠陥があります。 SQLパーサーを書きたくないので、この機能を削除しています。これからは、文字列からテーブルを参照するときにActive Recordに明示的に伝えなければなりません。

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

これは確かではありませんが、Rails 4ではこれが私にとって役に立ちました。

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

Rails 4なら簡単です。

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

http://guides.rubyonrails.org/active_record_querying.html#not-conditions もご覧ください。

21
Tilo