回答:
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))
rails undefined method 'not_eq' for :confirmed_at:Symbol
..
where
条件はASTを構築するだけであり、each
またはのようなターミナルメソッドを押すまでデータベースにヒットしませんto_a
。クエリの作成はパフォーマンスの問題ではありません。あなたがデータベースから要求しているものは何ですか。
これはARelのバグではなく、ロジックのバグです。
ここに欲しいのは:
Foo.includes(:bar).where(Bar.arel_table[:id].not_eq(nil))
true
ブール値であるを返します。SQLeseで:id => true
あなたid = 1
を取得します。
field_name != 'NULL'
です。
id = 't'
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スニペットについて話しますが、パーサーでハッシュ条件が文字列に変更されたと思いますか?)、最後に参照を追加してください:
Foo.includes(:bar).where.not(bars: {id: nil}).references(:bar)
サポート終了の警告:文字列SQLスニペットで参照されているテーブル(次のいずれか...)を積極的にロードしているようです。例えば:
Post.includes(:comments).where("comments.title = 'foo'")
現在、Active Recordは文字列内のテーブルを認識し、コメントを別のクエリに読み込むのではなく、コメントテーブルをクエリに結合することを認識しています。ただし、本格的なSQLパーサーを作成せずにこれを行うと、本質的に欠陥があります。SQLパーサーを作成したくないので、この機能を削除します。今後は、文字列からテーブルを参照するときに、Active Recordに明示的に通知する必要があります。
Post.includes(:comments).where("comments.title = 'foo'").references(:comments)
references
コールが助けてくれました!
Rails 4なら簡単です。
Foo.includes(:bar).where.not(bars: {id: nil})
参照:http : //guides.rubyonrails.org/active_record_querying.html#not-conditions
!nil
true
Rubyで評価され、ARel はSQLクエリで変換true
さ1
れます。したがって、生成されたクエリは実際に要求したものです-これはARelのバグではありませんでした。