【问题标题】:rails 3 - 'or' scopesrails 3 - '或' 范围
【发布时间】:2011-07-26 08:51:34
【问题描述】:

我们正在更新 rails 2 应用程序。我们一直很高兴使用fake_arel,它提供了一个非常好的“或”范围。

现在,使用 rails 3,我找不到复制它的方法。

我们有这样的代码:

scope.or(Event.horse, Event.dog, Event.trap).today

模型如下所示:

class Event < ActiveRecord::Base
 named_scope :horse, lambda { {:conditions => ["sport_category_id in (?)", SportCategory.find_horse_ids] }}
 named_scope :dog, lambda { {:conditions => ["sport_category_id in (?)", SportCategory.find_dog_ids] }}
 named_scope :trap, lambda { {:conditions => ["sport_category_id in (?)", SportCategory.find_trap_ids] }}
end

这些作用域需要分开并在各处使用。这个模型其实上面有几十个作用域组合使用,所以我们最不想做的就是全部重写。

您不能将作用域“或”在一起似乎很奇怪。

有人可以提出一种在 Rails 3 中也能做到这一点的方法吗?即使使用 arel 我也不知道该怎么做。 我们在另一个项目中使用 meta_where,但它也不提供任何此类功能。

【问题讨论】:

    标签: ruby-on-rails-3 activerecord scope


    【解决方案1】:

    嗯,这样做的方法是,在您的模型中(根据您的需要调整它!):

    where(:event => ['horse', 'dog', 'trap'])
    

    一个数组会产生一个 IN 语句,这就是你想要的。此外,您可以使用 rails 3 范围来实现:

    scope :my_scope, where(:event => ['horse', 'dog', 'trap'])
    

    那么你可以这样使用它:

    mymodel.my_scope # and possibility to chain, like :
    mymodel.my_scope.where(:public => true)
    

    【讨论】:

    • 也许我不明白该放在哪里。如果我把它放在我的事件模型上(像这样:scope :find_scope, where(:event => ['horse', 'dog', 'trap']))我得到: ActiveRecord::StatementInvalid: No attribute named @987654324 @ 存在于表 events
    • 这就是我写的原因:适应你的需要!如果你在这里发布你的模型,我会帮你弄清楚。
    • 我已经更新了模型。我看不出你在做什么以任何方式调用现有范围,这是整个问题。
    • 我明白了。您想将您的范围合并在一起。我不知道如何做到这一点,对不起。我的答案是创建一个有点“静态”的范围。
    • 该死!那好吧。也许比我更聪明的人可以将代码从 fake_arel 移植到 arel!
    【解决方案2】:

    我从 fake_arel 中提取了 'or' 函数并让它与 rails 3.0x 一起使用(不确定它是否可以与 3.1 一起使用,因为我们在这里不使用它)

    如果有人感兴趣,我已将其放入gist

    【讨论】:

      【解决方案3】:

      我无法从 Phil 工作的 Github-gist 获取代码,但它启发了我想出以下内容,我认为这是一个更简单的解决方案。它使用返回 ActiveRecord::Relation 类的类方法。

      def self.or alt_scope
        either = scoped.where_clauses.join(' AND ') 
        alternative = alt_scope.where_clauses.join(' AND ')
      
        Locatie.unscoped.where("(#{either}) OR (#{alternative})").
          joins(scoped.joins_values).joins(alt_scope.joins_values).
          group(scoped.group_values).group(alt_scope.group_values).
          having(scoped.having_values).having(alt_scope.having_values).
          includes(scoped.includes_values).includes(alt_scope.includes_values).
          order(scoped.order_values).order(alt_scope.order_values).
          select(scoped.select_values).select(alt_scope.select_values)
      end
      

      只需将此添加到您的课程中即可。然后,您将能够创建多个 OR 查询,如下所示:

      Event.horse.or(Event.dog).or(Event.trap)
      

      因此您可以将其“存储”在范围内:

      scope :horse_dog_or_trap, horse.or(Event.dog).or(Event.trap)
      

      并进一步扩大范围,例如:

      Event.horse.or(Event.dog).or(Event.trap).today
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-11-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-14
        • 2011-10-27
        相关资源
        最近更新 更多