ActiveRecord保持范围封装
问题描述:
我有两种型号,foo
和bar
,foo
有很多bars
。ActiveRecord保持范围封装
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
答
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,使这个对象合作,以使每个查询对象需要封装与其相应的模型逻辑的照顾。
其实我觉得你可能有它们混合起来。 – DanneManne 2011-01-20 03:39:20