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

Kos*_*tas 11 sql ruby-on-rails arel ruby-on-rails-3

假设我们有以下内容:

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

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

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

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

Zab*_*bba 17

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

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))
Run Code Online (Sandbox Code Playgroud)


Ant*_*pov 6

在轨道4中not,为此目的有后缀:

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

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

Post.where{ hidden != true }.to_sql
# => SELECT FROM `posts` WHERE `posts`.`hidden` != 1
Run Code Online (Sandbox Code Playgroud)


sun*_*aku 5

我们可以通过将反向查询传递回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
Run Code Online (Sandbox Code Playgroud)

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


Mar*_*n13 5

invert_where(Rails 7+)

从 Rails 7 开始,有一个新的invert_where方法。

根据文档,它:

允许您反转整个 where 子句,而不是手动应用条件。

class User
  scope :active, -> { where(accepted: true, locked: false) }
end

User.where(accepted: true)
# WHERE `accepted` = 1

User.where(accepted: true).invert_where
# WHERE `accepted` != 1

User.active
# WHERE `accepted` = 1 AND `locked` = 0

User.active.invert_where
# WHERE NOT (`accepted` = 1 AND `locked` = 0)
Run Code Online (Sandbox Code Playgroud)

请小心,因为这会反转 invert_where 调用之前的所有条件。

class User
  scope :active, -> { where(accepted: true, locked: false) }
  scope :inactive, -> { active.invert_where } # Do not attempt it
end

# It also inverts `where(role: 'admin')` unexpectedly.
User.where(role: 'admin').inactive
# WHERE NOT (`role` = 'admin' AND `accepted` = 1 AND `locked` = 0)
Run Code Online (Sandbox Code Playgroud)

资料来源: