У меня есть простой полиморфизм, где каждый подкласс имеет область действия 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
комбинированных областей (объединенных по ИЛИ) критериев dead
каждого потомка, поэтому я мог бы просто сделать
Animal.dead.count
Есть идеи, как это можно реализовать?
Если бы я использовал DataMapper, у него была бы хорошая функция, позволяющая комбинировать области действия/"ИЛИ" вместе. используя +
или |
(оператор объединения). Я не смог определить, есть ли у 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 и все другие доступные помощники.