File tree Expand file tree Collapse file tree 3 files changed +82
-10
lines changed
lib/mongoid/association/embedded
spec/integration/associations Expand file tree Collapse file tree 3 files changed +82
-10
lines changed Original file line number Diff line number Diff line change @@ -313,18 +313,19 @@ def selector
313313 #
314314 # @return [ Array<Hash> ] The documents as an array of hashes.
315315 def pre_process_batch_insert ( docs )
316- docs . map do |doc |
317- next unless doc
318- append ( doc )
319- if persistable? && ! _assigning?
320- self . path = doc . atomic_path unless path
321- if doc . valid? ( :create )
322- doc . run_before_callbacks ( :save , :create )
323- else
324- self . inserts_valid = false
316+ [ ] . tap do |results |
317+ append_many ( docs ) do | doc |
318+ if persistable? && ! _assigning?
319+ self . path = doc . atomic_path unless path
320+ if doc . valid? ( :create )
321+ doc . run_before_callbacks ( :save , :create )
322+ else
323+ self . inserts_valid = false
324+ end
325325 end
326+
327+ results << doc . send ( :as_attributes )
326328 end
327- doc . send ( :as_attributes )
328329 end
329330 end
330331
Original file line number Diff line number Diff line change @@ -443,6 +443,36 @@ def append(document)
443443 execute_callback :after_add , document
444444 end
445445
446+ # Optimized version of #append that handles multiple documents
447+ # in a more efficient way.
448+ def append_many ( documents , &block )
449+ id_of = -> ( doc ) { doc . _id || doc . object_id }
450+
451+ visited_docs = Set . new ( _target . map ( &id_of ) )
452+ next_index = _unscoped . size
453+
454+ unique_set = documents . select do |doc |
455+ next unless doc
456+ next if visited_docs . include? ( id_of [ doc ] )
457+
458+ execute_callback :before_add , doc
459+
460+ visited_docs . add ( id_of [ doc ] )
461+ integrate ( doc )
462+
463+ doc . _index = next_index
464+ next_index += 1
465+
466+ block . call ( doc ) if block
467+ end
468+
469+ _unscoped . concat ( unique_set )
470+ _target . push ( *scope ( unique_set ) )
471+ update_attributes_hash
472+
473+ unique_set . each { |doc | execute_callback :after_add , doc }
474+ end
475+
446476 # Instantiate the binding associated with this association.
447477 #
448478 # @example Create the binding.
Original file line number Diff line number Diff line change 201201 include_examples 'persists correctly'
202202 end
203203 end
204+
205+ context 'including duplicates in the assignment' do
206+ let ( :canvas ) do
207+ Canvas . create! ( shapes : [ Shape . new ] )
208+ end
209+
210+ shared_examples 'persists correctly' do
211+ it 'persists correctly' do
212+ canvas . shapes . length . should eq 2
213+ _canvas = Canvas . find ( canvas . id )
214+ _canvas . shapes . length . should eq 2
215+ end
216+ end
217+
218+ context 'via assignment operator' do
219+ before do
220+ canvas . shapes = [ canvas . shapes . first , Shape . new , canvas . shapes . first ]
221+ canvas . save!
222+ end
223+
224+ include_examples 'persists correctly'
225+ end
226+
227+ context 'via attributes=' do
228+ before do
229+ canvas . attributes = { shapes : [ canvas . shapes . first , Shape . new , canvas . shapes . first ] }
230+ canvas . save!
231+ end
232+
233+ include_examples 'persists correctly'
234+ end
235+
236+ context 'via assign_attributes' do
237+ before do
238+ canvas . assign_attributes ( shapes : [ canvas . shapes . first , Shape . new , canvas . shapes . first ] )
239+ canvas . save!
240+ end
241+
242+ include_examples 'persists correctly'
243+ end
244+ end
204245 end
205246
206247 context 'when an anonymous class defines an embeds_many association' do
You can’t perform that action at this time.
0 commit comments