使用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)"

这绝对不是我需要的,几乎看起来像一个bug在ARel。


Rails 4 +。

ActiveRecord 4.0及以上版本添加了where。但你不能这样做:

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

在处理表之间的作用域时,我更喜欢利用合并,这样就可以更容易地使用现有的作用域。

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

此外,由于includes并不总是选择连接策略,因此在这里也应该使用引用,否则可能会使用无效的SQL。

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

Rails 3

Rails 3的规范方法是:

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

这不是ARel中的错误,而是逻辑中的错误。

你想要的是:

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

Rails4:

所以,你想要的是一个内部连接,所以你应该只使用joins谓词:

  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)

DEPRECATION WARNING: It looks like you are eager loading table(s) (one of: ....) that are referenced in a string SQL snippet. For example: Post.includes(:comments).where("comments.title = 'foo'") Currently, Active Record recognizes the table in the string, and knows to JOIN the comments table to the query, rather than loading comments in a separate query. However, doing this without writing a full-blown SQL parser is inherently flawed. Since we don't want to write an SQL parser, we are removing this functionality. From now on, you must explicitly tell Active Record when you are referencing a table from a string: Post.includes(:comments).where("comments.title = 'foo'").references(:comments)

Rails 4很简单:

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

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

不确定这是有用的,但这是我在Rails 4工作

Foo.where.not(bar: nil)