如何使用或不创建rails范围?

时间:2013-01-11 14:40:35

标签: ruby-on-rails ruby

我的用户模型中有两个范围:

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。

3 个答案:

答案 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)

请参阅:Is it possible to invert a named scope in Rails3?

答案 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}}这样的'糖'宝石