การรวมขอบเขตโมเดล polymorphic Mongoid ในคลาสพื้นฐานหรือไม่

ฉันมีความหลากหลายเล็กน้อยโดยแต่ละคลาสย่อยมีขอบเขต 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 ร่วมกัน) ของเกณฑ์ 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 และตัวช่วยอื่นๆ ทั้งหมดที่มีอยู่


person Abe Voelker    schedule 23.08.2013    source แหล่งที่มา


คำตอบ (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

อย่างไรก็ตาม ดูเหมือนว่าจะเป็นการแฮ็ก ฉันจะเปิดคำถามทิ้งไว้สักพักเผื่อใครมีข้อเสนอแนะที่สะอาดกว่านี้

person Abe Voelker    schedule 23.08.2013