Skip to content

Commit 0905ff4

Browse files
authored
Merge pull request #27 from cacheventures/polymorphic-assoc-eager-loading
Fix problem with eager loading polymorphic associations in mongoid 9
2 parents f08e867 + 7250765 commit 0905ff4

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed

lib/mongoid/includes/inclusion.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def load_documents_for(foreign_key, foreign_key_values)
5454
# Returns an Inclusion that can be eager loaded as usual.
5555
def for_class_name(class_name)
5656
Inclusion.new metadata.clone.instance_eval { |relation_metadata|
57+
@options = @options.dup
5758
@options[:class_name] = @class_name = class_name
5859
@options[:polymorphic], @options[:as], @polymorphic, @klass = nil
5960
self

spec/mongoid/includes/polymorphic_includes_spec.rb

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,117 @@
5656
}.to raise_error(Mongoid::Includes::Errors::InvalidPolymorphicIncludes)
5757
end
5858
end
59+
60+
context 'eager loading polymorphic belongs_to associations with multiple concrete types' do
61+
before(:context) do
62+
class Main
63+
include Mongoid::Document
64+
belongs_to :related, polymorphic: true, optional: true
65+
end
66+
67+
class Related
68+
include Mongoid::Document
69+
has_one :parent, as: :related
70+
end
71+
72+
class Two < Related; end
73+
class Three < Related; end
74+
end
75+
76+
after(:context) do
77+
%i[Main Related Two Three].each do |const|
78+
Object.send(:remove_const, const) if Object.const_defined?(const, false)
79+
end
80+
end
81+
82+
it 'loads the related documents for each concrete type without raising' do
83+
Main.create!(related: Two.create!)
84+
Main.create!(related: Three.create!)
85+
86+
loaded = nil
87+
expect { loaded = Main.includes(:related).entries }.not_to raise_error
88+
expect(loaded.map { |doc| doc.related.class }).to match_array([Two, Three])
89+
expect { Main.last.related.id }.not_to raise_error
90+
end
91+
end
92+
93+
context 'polymorphic eager loading in a fresh Ruby process' do
94+
let(:project_root) { File.expand_path('../../..', __dir__) }
95+
96+
it 'does not error when includes is evaluated from the CLI' do
97+
require 'open3'
98+
99+
database_name = "mongoid_includes_spec_#{SecureRandom.hex(6)}"
100+
base_script = <<~RUBY
101+
require 'bundler/setup'
102+
require 'mongoid'
103+
require 'mongoid_includes'
104+
105+
Mongoid.load_configuration(
106+
clients: {
107+
default: {
108+
database: '#{database_name}',
109+
hosts: %w[localhost:27017]
110+
}
111+
}
112+
)
113+
114+
class Main
115+
include Mongoid::Document
116+
belongs_to :related, polymorphic: true, optional: true
117+
end
118+
119+
class Related
120+
include Mongoid::Document
121+
has_one :parent, as: :related
122+
end
123+
124+
class Two < Related; end
125+
class Three < Related; end
126+
RUBY
127+
128+
init_script = base_script + <<~RUBY
129+
client = Mongoid::Clients.default
130+
begin
131+
client.database.drop
132+
rescue Mongo::Error::OperationFailure
133+
end
134+
135+
Main.destroy_all
136+
Related.destroy_all
137+
138+
Main.create!(related: Two.create!)
139+
Main.create!(related: Three.create!)
140+
RUBY
141+
142+
bad_script = base_script + <<~RUBY
143+
Main.includes(:related).entries
144+
Main.last.related.id
145+
146+
Mongoid::Clients.default.database.drop
147+
RUBY
148+
149+
bundle_gemfile = ENV.fetch(
150+
'BUNDLE_GEMFILE',
151+
File.join(project_root, 'Gemfile')
152+
)
153+
154+
run_script = lambda do |script|
155+
Open3.capture2e(
156+
{ 'BUNDLE_GEMFILE' => bundle_gemfile },
157+
RbConfig.ruby,
158+
'-',
159+
chdir: project_root,
160+
stdin_data: script
161+
)
162+
end
163+
164+
init_out, init_status = run_script.call(init_script)
165+
expect(init_status).to be_success, "failed to prepare polymorphic data: #{init_out}"
166+
167+
bad_out, bad_status = run_script.call(bad_script)
168+
expect(bad_status).to be_success, "expected CLI reproduction to succeed, got #{bad_status.exitstatus}: #{bad_out}"
169+
end
170+
end
59171
end
60172
end

0 commit comments

Comments
 (0)