2013-08-23 28 views
2

我有一個簡單的多態性位,其中每個子類都有一個dead作用域,每個實現略有不同。我想是能夠從dead類方法他們聚集所有從基類:在基類中結合多態的Mongoid模型作用域?

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方法返回的每一個後代的dead標準合併範圍(OR連起來)的定期Mongoid::Criteria,所以我可以簡單地做

Animal.dead.count 

如何實現這一點的任何想法?

如果我使用DataMapper,它有一個nice feature,您可以在其中使用+|(聯合運算符)將「/」作用域組合在一起。我無法確定Mongoid是否有這樣的功能,但是如果這樣做,我認爲這可以解決我的問題。

這裏是我所追求的快速的RSpec規格:我使用的Rails

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 

所以你可以認爲我擁有的ActiveSupport和所有其他傭工可用。

回答

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的。如果有人有任何更清晰的建議,我會將問題留待一段時間。