我有一个简单的多态性,其中每个子类都有一个dead
范围,每个都有不同的实现。我希望能够从基类的dead
类方法中收集它们:
class Animal
include Mongoid::Document
field :birthday, type: DateTime
def self.dead
descendants.map(&:dead)
end
end
class Dog < Animal
scope :dead, ->{ where(birthday: { :$lt => Time.now - 13.years }) }
end
class GuineaPig < Animal
scope :dead, ->{ where(birthday: { :$lt => Time.now - 4.years }) }
end
class Turtle < Animal
scope :dead, ->{ where(birthday: { :$lt => Time.now - 50.years }) }
end
根据定义,Animal::dead
方法返回一个包含每个后代模型范围标准的数组:
>> Animal.dead
=> [#<Mongoid::Criteria
selector: {"birthday"=>{:$lt=>2000-08-23 14:39:24 UTC}}
options: {}
class: Dog
embedded: false>
, #<Mongoid::Criteria
selector: {"birthday"=>{:$lt=>2009-08-23 14:39:24 UTC}}
options: {}
class: GuineaPig
embedded: false>
, #<Mongoid::Criteria
selector: {"birthday"=>{:$lt=>1963-08-23 14:39:24 UTC}}
options: {}
class: Turtle
embedded: false>
]
如果我想要计算所有死去的动物,我必须做这样的事情:
Animal.dead.map(&:count).reduce(:+)
我更喜欢的是,如果我的Animal::dead
方法返回了每个后代的Mongoid::Criteria
条件的合并范围(ORed together)的常规dead
,那么我可以简单地
Animal.dead.count
关于如何实施这一点的任何想法?
如果我使用DataMapper,它有一个nice feature,您可以使用+
或|
(union运算符)将/“OR”范围组合在一起。我无法确定Mongoid是否有这样的功能,但如果确实如此,我认为这可以解决我的问题。
这是我所追求的快速RSpec规范:
describe Animal.dead do
it { should respond_to(:count, :all, :first, :destroy) }
end
describe Animal do
before do
Animal.all.destroy
# create 1 dead dog, 2 dead guinea pigs, 3 dead turtles (total 6)
1.times{ Dog.create(birthday: Time.now - 20.years) }
2.times{ GuineaPig.create(birthday: Time.now - 5.years) }
3.times{ Turtle.create(birthday: Time.now - 100.years) }
# create 3 alive dogs
3.times{ Dog.create(birthday: Time.now - 6.years) }
end
it 'should combine descendant animal dead scopes' do
expect(Animal.dead.count).to eq(6)
end
end
我正在使用Rails,因此您可以假设我有ActiveSupport和所有其他帮助程序。
答案 0 :(得分:1)
我有一个似乎有效的临时解决方案:
class Animal
include Mongoid::Document
field :birthday, type: DateTime
def self.dead
self.or(*descendants.map{|d| d.dead.type(d).selector})
end
end
然而,它似乎是hackish。如果有人提出任何更清晰的建议,我会暂时搁置这个问题。