我的用户模型中有两个范围:
scope :hard_deactivated, where(:hard_deactivated => true)
scope :soft_deactivated, where(:soft_deactivated => true)
到目前为止一切顺利
我想创建一个范围:已停用,其中包括hard_deactivated为true或软关闭为true的所有用户。显然我可以这样做:
scope :deactivated, where("hard_deactivated = ? or soft_deactivated = ?", true, true)
但这感觉不是很干。
另外我想创建一个反范围:not_hard_deactivated。我能做到这一点:
scope :not_hard_deactivated, where(:hard_deactivated => false)
但同样,这感觉很糟糕,特别是如果我的范围变得更加复杂。应该有一些方法或扭曲前一个范围在not子句中生成的SQL。
答案 0 :(得分:3)
使用arel表:
hard_deactivated_true = arel_table[:hard_deactivated].eq(true)
soft_deactivated_true = arel_table[:soft_deactivated].eq(true)
scope :deactivated, where(hard_deactivated_true.and(soft_deactivated_true))
scope :not_hard_deactivated, where(hard_deactivated_true.not)
答案 1 :(得分:1)
对于“NOT”部分,您可以执行以下操作:
extend ScopeUtils
positive_and_negative_scopes :deactivated do |value|
where(:hard_deactivated => value)
end
在单独的模块中实现此方法:
module ScopeUtils
def positive_and_negative_scopes(name)
[true, false].each do |filter_value|
prefix = ("not_" if filter_value == false)
scope :"#{prefix}#{name}", yield(filter_value)
end
end
end
关于“OR”情况,您可能会有类似的情况,具体取决于您的重复模式。在上面的简单示例中,它不值得,因为无法提供可读性。
scopes_with_adjectives_and_negatives :deactivated, [:soft, :hard]
module ScopeUtils
def scopes_with_adjectives_and_negatives(name, kinds)
kinds.each do |kind|
positive_and_negative_scopes name do |filter_value|
where("#{kind}_#{name}" => filter_value)
end
end
scope :"#{name}", where(kinds.map{|kind| "#{kind}_#{name} = ?"}.join(" OR "), true, true)
scope :"not_#{name}", where(kinds.map{|kind| "#{kind}_#{name} = ?"}.join(" AND "), false, false)
end
end
答案 2 :(得分:0)
你应该在where
方法中使用sql片段(就像在你的第二个例子中一样),或者更多像'{3}}这样的'糖'宝石