我有两个模型,foo
和bar
,foo
有很多bars
。
Bar
是在给定时间段内发生的事件,所以我想要一个返回ActiveRecord::Relation
的方法或范围来表示当前有效条形图的foos。
在具有范围的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
属性?
答案 0 :(得分: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
答案 1 :(得分:0)
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
答案 2 :(得分:0)
如果要封装查询对象,我编写了一个微型库,可以非常简单地将复杂的查询逻辑移到模型和控制器之外。
https://github.com/ElMassimo/queryable
它负责使您的作用域可链接,并将每个方法委托给实际查询。
对于这种情况,您可以有两个查询对象,FooQuery和BarQuery,并使这些对象协作,以便每个查询对象负责封装与其相应模型相关的逻辑。