Skip to content

Commit df399bc

Browse files
committed
MONGOID-5839 Fix eager-loading from STI subclasses
If the root of a query is an STI subclass (e.g. `Subclass.all`) AND the query tries to eager load (`includes`) another association, the eager load was failing because it was looking for inverse associations using the STI subclass name, instead of the class at the root of the hierarchy.
1 parent ec18c8b commit df399bc

File tree

3 files changed

+39
-2
lines changed

3 files changed

+39
-2
lines changed

lib/mongoid/association/eager_loadable.rb

+3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ def preload(associations, docs)
4242
docs_map = {}
4343
queue = [ klass.to_s ]
4444

45+
# account for single-collection inheritance
46+
queue.push(klass.root_class.to_s) if klass != klass.root_class
47+
4548
while klass = queue.shift
4649
if as = assoc_map.delete(klass)
4750
as.each do |assoc|

lib/mongoid/traversable.rb

+12
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ def hereditary?
4444
!!(superclass < Mongoid::Document)
4545
end
4646

47+
# Returns the root class of the STI tree that the current
48+
# class participates in. If the class is not an STI subclass, this
49+
# returns the class itself.
50+
#
51+
# @return [ Mongoid::Document ] the root of the STI tree
52+
def root_class
53+
root = self
54+
root = root.superclass while root.hereditary?
55+
56+
root
57+
end
58+
4759
# When inheriting, we want to copy the fields from the parent class and
4860
# set the on the child to start, mimicking the behavior of the old
4961
# class_inheritable_accessor that was deprecated in Rails edge.

spec/mongoid/association/eager_spec.rb

+24-2
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,36 @@
1515
Mongoid::Contextual::Mongo.new(criteria)
1616
end
1717

18+
let(:association_host) { Account }
19+
1820
let(:inclusions) do
1921
includes.map do |key|
20-
Account.reflect_on_association(key)
22+
association_host.reflect_on_association(key)
2123
end
2224
end
2325

2426
let(:doc) { criteria.first }
2527

28+
context 'when root is an STI subclass' do
29+
# Driver has_one Vehicle
30+
# Vehicle belongs_to Driver
31+
# Truck is a Vehicle
32+
33+
before do
34+
Driver.create!(vehicle: Truck.new)
35+
end
36+
37+
let(:criteria) { Truck.all }
38+
let(:includes) { %i[ driver ] }
39+
let(:association_host) { Truck }
40+
41+
it 'preloads the driver' do
42+
expect(doc.ivar(:driver)).to be false
43+
context.preload(inclusions, [ doc ])
44+
expect(doc.ivar(:driver)).to be == Driver.first
45+
end
46+
end
47+
2648
context "when belongs_to" do
2749

2850
let!(:account) do
@@ -43,7 +65,7 @@
4365
it "preloads the parent" do
4466
expect(doc.ivar(:person)).to be false
4567
context.preload(inclusions, [doc])
46-
expect(doc.ivar(:person)).to eq(doc.person)
68+
expect(doc.ivar(:person)).to be == person
4769
end
4870
end
4971

0 commit comments

Comments
 (0)