【问题标题】:ActiveRecord keeping scope encapsulatedActiveRecord 保持范围封装
【发布时间】:2011-01-20 02:58:29
【问题描述】:

我有两个模型,foobarfoo 有很多 bars

Bar 是在给定时间段内发生的事件,所以我想要一个返回 ActiveRecord::Relation 的方法或作用域,表示当前具有活动栏的 foo。

这在Foo 类中很简单,有一个作用域:

class Foo < ActiveRecord::Base
has_many :bars

scope :has_current_bars, joins(:bars).where('bar.foo_id IS NOT NULL').where('bar.starts_at <= ?', DateTime.now).where('bar.ends_at >= ?', DateTime.now)

我不喜欢这一点,foo 需要非常了解 bar 的内部结构。

这可以重写吗,可能通过在bar 上添加一个范围,所以foo 不需要知道bar 属性?

【问题讨论】:

    标签: ruby-on-rails activerecord named-scope arel


    【解决方案1】:

    当然。您可以而且应该将范围移动到 Bar

    class Bar < ActiveRecord::Base
      belongs_to :foo
    
      scope :current, where('starts_at <= ? AND ends_at >= ?', DateTime.now, DateTime.now)
    end
    
    foo = Foo.first
    foo.bars.current # Will return all of foo's bars which match the scope
    
    # EDIT:
    bars.current.map(&:foo) # Will return all foos that have current bars
    

    【讨论】:

    • 实际上,我想你可能把它们弄混了。
    • 这和我的有点不同。我的返回具有当前柱的 foos。正如您所提到的,您的返回当前柱,给定一个 foo
    • @SooDesuNe 查看我的编辑,了解如何使用当前条形获取所有 foos。
    • @vonconrad,感谢您的关注。我们正朝着正确的方向前进,不幸的是,bars.current.map(&:foo) 返回一个数组,而不是 ActiveRecord::Relation,因此在此之后所有链接都已失效。
    • @SooDesuNe 在获取具有当前柱的那些之后,你需要对 foo 做什么?换句话说,为什么你需要它是一个 ActiveRecord::Relation?
    【解决方案2】:
    class Foo < ActiveRecord::Base
      has_many :bars
    
      def self.has_current_bars
        joins(:bars).merge(Bar.current)
      end
    
      # or
      scope :has_current_bars, joins(:bars).merge(Bar.current)
    end
    
    class Bar < ActiveRecord::Base
      scope :current, where('bar.starts_at <= ?', DateTime.now).where('bar.ends_at >= ?', DateTime.now)
    end
    
    foos = Foo.has_current_bars
    

    【讨论】:

      【解决方案3】:

      如果您想封装查询对象,我已经编写了一个微型库,它可以非常简单地将复杂的查询逻辑移到模型和控制器之外。

      https://github.com/ElMassimo/queryable

      它负责使您的范围可链接,并委托像 each 和映射到实际查询的方法。

      对于这种情况,您可以有两个查询对象,FooQuery 和 BarQuery,并让这些对象协作,以便每个查询对象负责封装与其对应模型相关的逻辑。

      【讨论】:

        猜你喜欢
        • 2014-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多