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 /方法(需要true或false作为参数)的情况下获得范围的反面?
像这样的东西:
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)
它将使用子查询.
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的狂热者,那么就这样吧.
虽然我不认为使用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)
您可以通过编程方式执行此操作,无需子查询:
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)不会被否定。