我有一个简单的多态性,其中每个子类都有一个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操作符)将/“或”作用域组合在一起。我无法确定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和所有其他可用的帮助程序。

最佳答案

我有一个暂时的解决办法,似乎奏效了:

class Animal
  include Mongoid::Document
  field :birthday, type: DateTime

  def self.dead
    self.or(*descendants.map{|d| d.dead.type(d).selector})
  end
end

不过,这似乎有点老套。如果有人有更清楚的建议,我会暂时不提这个问题。

关于ruby - 在基类中合并多态Mongoid模型范围?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18406435/

10-14 19:33