有没有办法反转ActiveRecord :: Relation查询?

假设我们有以下内容:

irb> Post.where(:hidden => true).to_sql => "SELECT `posts`.* FROM `posts` WHERE posts.hidden = 1" 

我们能以某种方式得到一个倒置的SQL查询吗?

我在寻找什么,应该是这样的:

 irb> Post.where(:hidden => true).invert.to_sql => "SELECT `posts`.* FROM `posts` WHERE NOT (posts.hidden = 1)" 

使用不同的语法,是的。 例:

 posts = Post.scoped.table # or Arel::Table.new("posts") posts.where(posts[:hidden].eq(true).not).to_sql # => SELECT FROM `posts` WHERE NOT ((`posts`.`hidden` = 1)) 

在rails 4中not用于此目的的后缀:

 Post.where.not(hidden: true).to_sql # => SELECT FROM `posts` WHERE `posts`.`hidden` != 1 

在rails 3中你可以使用squeel gem 。 它提供了许多有用的function。 有了它,你可以写:

 Post.where{ hidden != true }.to_sql # => SELECT FROM `posts` WHERE `posts`.`hidden` != 1 

我们可以通过将反向查询传递回ActiveRecord来进一步获取Zabba的答案 :

 table = Post.arel_table query = table[:hidden].eq(true).not # the inverted query, still ARel Post.where(query) # plug it back into ActiveRecord 

这将返回ActiveRecord对象,正如您通常所期望的那样。

当我在寻找具有“不真实”条件(例如,假或零)的记录时,我所做的是:

 Post.where(["(hidden IS NULL) OR (hidden = ?)", false]) 

对于单表查询,这将工作:

 query = Post.where(hidden:true) inverse = Post.where('id not in (?)', query.pluck(:id)) 

当然,我们遇到了可怕的效率问题,并且它不会生成您要求的SQL查询(尽管在运行时,它最终会产生相同的结果集)。