条件使用NOT NULL的Rails

Soo*_*uNe 355 ruby-on-rails arel rails-activerecord

使用rails 3样式我怎么写相反的:

Foo.includes(:bar).where(:bars=>{:id=>nil})
Run Code Online (Sandbox Code Playgroud)

我想找到id为非null的地方.我试过了:

Foo.includes(:bar).where(:bars=>{:id=>!nil}).to_sql
Run Code Online (Sandbox Code Playgroud)

但那回归:

=> "SELECT     \"foos\".* FROM       \"foos\"  WHERE  (\"bars\".\"id\" = 1)"
Run Code Online (Sandbox Code Playgroud)

这绝对不是我需要的,而且几乎看起来像是ARel中的一个错误.

Ada*_*sek 502

使用Rails 3执行此操作的规范方法:

Foo.includes(:bar).where("bars.id IS NOT NULL")
Run Code Online (Sandbox Code Playgroud)

ActiveRecord 4.0及更高版本添加,where.not所以你可以这样做:

Foo.includes(:bar).where.not('bars.id' => nil)
Foo.includes(:bar).where.not(bars: { id: nil })
Run Code Online (Sandbox Code Playgroud)

在表之间使用作用域时,我更喜欢利用它,merge以便我可以更轻松地使用现有作用域.

Foo.includes(:bar).merge(Bar.where.not(id: nil))
Run Code Online (Sandbox Code Playgroud)

此外,由于includes并不总是选择连接策略,因此您也应该使用references此处,否则您最终可能会使用无效的SQL.

Foo.includes(:bar)
   .references(:bar)
   .merge(Bar.where.not(id: nil))
Run Code Online (Sandbox Code Playgroud)

  • @Tim是的,我上面链接的MetaWhere gem. (3认同)
  • 我喜欢不需要其他宝石的解决方案:)即使它有点难看 (3认同)
  • AR 4.*信息为+1.很有用. (3认同)

Rya*_*igg 250

它不是ARel中的错误,它是你逻辑中的一个错误.

你想要的是:

Foo.includes(:bar).where(Bar.arel_table[:id].not_eq(nil))
Run Code Online (Sandbox Code Playgroud)

  • 这个,IMO,优于公认的答案. (32认同)
  • 猜测,!nil返回`true`,这是一个布尔值.`:id => true`在SQLese中获得`id = 1`. (12认同)
  • 我很好奇那个转向的逻辑是什么!nil变为'1' (2认同)

Mat*_*ish 36

对于Rails4:

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

  Foo.joins(:bar)

  Select * from Foo Inner Join Bars ...
Run Code Online (Sandbox Code Playgroud)

但是,对于记录,如果你想要一个"NOT NULL"条件,只需使用not predicate:

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

Select * from Foo Left Outer Join Bars on .. WHERE bars.id IS NOT NULL
Run Code Online (Sandbox Code Playgroud)

请注意,此语法报告了弃用(它讨论了字符串SQL片段,但我想在解析器中将哈希条件更改为字符串?),因此请务必将引用添加到结尾:

Foo.includes(:bar).where.not(bars: {id: nil}).references(:bar)
Run Code Online (Sandbox Code Playgroud)

弃用警告:看起来您正急切地加载在字符串SQL片段中引用的表(......之一:....).例如:

Post.includes(:comments).where("comments.title = 'foo'")
Run Code Online (Sandbox Code Playgroud)

目前,Active Record识别字符串中的表,并且知道将comments表连接到查询,而不是在单独的查询中加载注释.但是,在不编写完整的SQL解析器的情况下执行此操作本身就存在缺陷.由于我们不想编写SQL解析器,因此我们将删除此功能.从现在开始,当您从字符串引用表时,必须明确告诉Active Record:

Post.includes(:comments).where("comments.title = 'foo'").references(:comments)
Run Code Online (Sandbox Code Playgroud)


Rae*_*fat 25

不确定这是否有用,但这对我在Rails 4中有用

Foo.where.not(bar: nil)
Run Code Online (Sandbox Code Playgroud)

  • 这是这里最好的答案。-- 2017 https://robots.thoughtbot.com/activerecords-wherenot (2认同)

Til*_*ilo 21

使用Rails 4很容易:

 Foo.includes(:bar).where.not(bars: {id: nil})
Run Code Online (Sandbox Code Playgroud)

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