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