ActiveRecord保持范围封装

问题描述:

我有两种型号,foobarfoo有很多barsActiveRecord保持范围封装

Bar是发生一段时间的事件,所以我想要一个方法或范围返回代表当前有活动酒吧的foos的ActiveRecord::Relation

这是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属性?

绝对。您可以也应该将范围移至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 
+0

其实我觉得你可能有它们混合起来。 – DanneManne 2011-01-20 03:39:20

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 

如果你想你的封装查询对象,我写了一个微型图书馆,使得它非常简单的运动复杂的查询逻辑的模型和控制器之外。

https://github.com/ElMassimo/queryable

它负责使您的示波器可链接,并委托像每映射到实际的查询方法。

对于这种情况,你可以有两个查询对象,FooQuery和BarQuery,使这个对象合作,以使每个查询对象需要封装与其相应的模型逻辑的照顾。