我的班级名为Collection
:
scope :with_missing_coins, joins(:coins).where("coins.is_missing = ?", true)
我可以运行Collection.with_missing_coins.count
并获得结果 - 效果很好!
目前,如果我想获得不丢失硬币的收藏品,我会添加另一个范围:
scope :without_missing_coins, joins(:coins).where("coins.is_missing = ?", false)
我发现自己写了很多这些“相反”的范围。是否有可能在不牺牲可读性或使用lambda /方法(以true
或false
作为参数)的情况下获得范围的反面?
这样的事情:
Collection.!with_missing_coins
答案 0 :(得分:49)
在Rails 4.2中,你可以这样做:
scope :original, -> { ... original scope definition ... }
scope :not_original, -> { where.not(id: original) }
它将使用子查询。
答案 1 :(得分:11)
我不会为此使用单个范围,而是两个:
scope :with_missing_coins, joins(:coins).where("coins.is_missing = ?", true)
scope :without_missing_coins, joins(:coins).where("coins.is_missing = ?", false)
这样,当使用这些范围时,它就会明确地发生了什么。有了数字1311407建议的数字,false
对with_missing_coins
的{{1}}参数的作用并不是很清楚。
我们应该尝试尽可能清晰地编写代码,如果这意味着不再是关于DRY的狂热者,那么就这样吧。
答案 2 :(得分: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) }
然后:
Collection.with_missing_coins
Collection.without_missing_coins
答案 3 :(得分:0)
这可能只是行得通,并没有进行太多测试。使用rails 5我猜想rails 3具有where_values方法,而不是where_clause。
scope :not, ->(scope_name) { query = self
send(scope_name).joins_values.each do |join|
query = query.joins(join)
end
query.where((send(scope_name).where_clause.send(:predicates).reduce(:and).not))}
用法
Model.not(:scope_name)
答案 4 :(得分:0)
@bill-lipa 的回答很好,但是当您想要的范围涉及关联或附件时要小心。
如果我们有以下范围选择所有附有简历的用户:
scope :with_resume, -> { joins(:resume_attachment) }
如果 with_resume
为空,以下否定将导致异常:
scope :without_resume, -> { where.not(id: with_resume) }
#=> users.without_resume
#=> ActiveRecord::StatementInvalid (PG::InvalidColumnReference: ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
因此,您需要先检查以获得所需的结果:
scope :without_resume, -> { with_resume.any? ? where.not(id: with_resume) : where.not(id: []) }
答案 5 :(得分:-2)
更新。现在,Rails 6添加了方便又漂亮的负枚举方法。
# All inactive devices
# Before
Device.where.not(status: :active)
#After
Device.not_active
博客文章 here