是否有可能否定Rails 3中的范围?

Yuv*_*rmi 32 ruby named-scope ruby-on-rails

我的班级有以下范围Collection:

scope :with_missing_coins, joins(:coins).where("coins.is_missing = ?", true)
Run Code Online (Sandbox Code Playgroud)

我可以跑步Collection.with_missing_coins.count并得到一个结果 - 它很棒!目前,如果我想获得不丢失硬币的收藏品,我会添加另一个范围:

scope :without_missing_coins, joins(:coins).where("coins.is_missing = ?", false)
Run Code Online (Sandbox Code Playgroud)

我发现自己写了很多这些"相反"的范围.是否有可能在不牺牲可读性或求助于lambda /方法(需要truefalse作为参数)的情况下获得范围的反面?

像这样的东西:

Collection.!with_missing_coins
Run Code Online (Sandbox Code Playgroud)

小智 63

在Rails 4.2中,您可以:

scope :original, -> { ... original scope definition ... }
scope :not_original, -> { where.not(id: original) }
Run Code Online (Sandbox Code Playgroud)

它将使用子查询.

  • 好主意但在我的情况下,子查询花了两倍的时间. (2认同)
  • 当然。那是因为它必须找到所有“原始”行的“id”,然后运行排除这些 id 的查询。即使 Rails 使用嵌套查询,它也做了两次工作 (2认同)

Rya*_*igg 12

我不会为此使用单个范围,而是两个:

scope :with_missing_coins, joins(:coins).where("coins.is_missing = ?", true)
scope :without_missing_coins, joins(:coins).where("coins.is_missing = ?", false)
Run Code Online (Sandbox Code Playgroud)

这样,当使用这些范围时,它就会明确地发生了什么.有了1311407号的建议,目前还不清楚这个false论点with_missing_coins是做什么的.

我们应该尝试尽可能清楚地编写代码,如果这意味着不再是关于DRY的狂热者,那么就这样吧.


num*_*407 7

虽然我不认为使用lambda方法是一个问题,但本身并没有"逆转"范围.

scope :missing_coins, lambda {|status| 
  joins(:coins).where("coins.is_missing = ?", status) 
}

# you could still implement your other scopes, but using the first
scope :with_missing_coins,    lambda { missing_coins(true) }
scope :without_missing_coins, lambda { missing_coins(false) }
Run Code Online (Sandbox Code Playgroud)

然后:

Collection.with_missing_coins
Collection.without_missing_coins
Run Code Online (Sandbox Code Playgroud)


thi*_*ign 5

您可以通过编程方式执行此操作,无需子查询:

scope :my_scope, ...

Entity.where.not(Entity.my_scope.where_values_hash)
Run Code Online (Sandbox Code Playgroud)

另请参阅:https://makandracards.com/makandra/486959-how-to-negate-scope-conditions-in-rails

请注意,这仅适用于 AR 查询,不适用于 SQL 查询。 例如where('updated_at < ?', 1.hour.ago)不会被否定。