2

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

scope :hard_deactivated, where(:hard_deactivated => true)
scope :soft_deactivated, where(:soft_deactivated => true)

到目前为止,一切都很好

或者

我想创建一个范围:deactivated,其中将包括 hard_deactivated 为 true 或 soft deactivated 为 true 的所有用户。显然我可以这样做:

scope :deactivated, where("hard_deactivated = ? or soft_deactivated = ?", true, true)

但这感觉不是很干。

不是

另外我想创建一个逆作用域:not_hard_deactivated。我可以这样做:

scope :not_hard_deactivated, where(:hard_deactivated => false)

但同样,这感觉很糟糕,尤其是当我的范围变得更复杂时。在 not 子句中应该有某种方式或扭曲前一个范围生成的 SQL。

4

3 回答 3

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)

请参阅:是否可以在 Rails3 中反转命名范围?

于 2013-01-11T15:09:16.783 回答
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
于 2013-01-11T15:08:56.737 回答
0

您应该在方法中使用 sql 片段where(如在第二个示例中),或者更多像squeel这样的“糖”宝石

于 2013-01-11T15:08:01.793 回答