Skip to content
This repository
Browse code

Backport #3329 to 3-2-stable

Fix bug with autosave collection association on new record with a marked
for destroy record in autosave collection.

Fixes #6918.
  • Loading branch information...
commit b1e509ad7a8c8264544f10f4666705cd806b5408 1 parent 9e0b3fc
Francesco Rodríguez authored July 02, 2012
36  activerecord/lib/active_record/autosave_association.rb
@@ -332,25 +332,31 @@ def save_collection_association(reflection)
332 332
 
333 333
         if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
334 334
           begin
335  
-          records.each do |record|
336  
-            next if record.destroyed?
  335
+            records_to_destroy = []
  336
+
  337
+            records.each do |record|
  338
+              next if record.destroyed?
  339
+
  340
+              saved = true
  341
+
  342
+              if autosave && record.marked_for_destruction?
  343
+                records_to_destroy << record
  344
+              elsif autosave != false && (@new_record_before_save || record.new_record?)
  345
+                if autosave
  346
+                  saved = association.insert_record(record, false)
  347
+                else
  348
+                  association.insert_record(record) unless reflection.nested?
  349
+                end
  350
+              elsif autosave
  351
+                saved = record.save(:validate => false)
  352
+              end
337 353
 
338  
-            saved = true
  354
+              raise ActiveRecord::Rollback unless saved
  355
+            end
339 356
 
340  
-            if autosave && record.marked_for_destruction?
  357
+            records_to_destroy.each do |record|
341 358
               association.proxy.destroy(record)
342  
-            elsif autosave != false && (@new_record_before_save || record.new_record?)
343  
-              if autosave
344  
-                saved = association.insert_record(record, false)
345  
-              else
346  
-                association.insert_record(record) unless reflection.nested?
347  
-              end
348  
-            elsif autosave
349  
-              saved = record.save(:validate => false)
350 359
             end
351  
-
352  
-            raise ActiveRecord::Rollback unless saved
353  
-          end
354 360
           rescue
355 361
             records.each {|x| IdentityMap.remove(x) } if IdentityMap.enabled?
356 362
             raise
10  activerecord/test/cases/autosave_association_test.rb
@@ -770,6 +770,16 @@ def destroy(*args)
770 770
     assert_equal before, @pirate.reload.birds
771 771
   end
772 772
 
  773
+  def test_when_new_record_a_child_marked_for_destruction_should_not_affect_other_records_from_saving
  774
+    @pirate = @ship.build_pirate(:catchphrase => "Arr' now I shall keep me eye on you matey!") # new record
  775
+
  776
+    3.times { |i| @pirate.birds.build(:name => "birds_#{i}") }
  777
+    @pirate.birds[1].mark_for_destruction
  778
+    @pirate.save!
  779
+
  780
+    assert_equal 2, @pirate.birds.reload.length
  781
+  end
  782
+
773 783
   # Add and remove callbacks tests for association collections.
774 784
   %w{ method proc }.each do |callback_type|
775 785
     define_method("test_should_run_add_callback_#{callback_type}s_for_has_many") do

0 notes on commit b1e509a

Alan Da Costa

It'd be nice if the collection to be operated on had its logic outside of the operations, so we don't have to follow logic like this "next" method. It seems like there are lots of different things going on here in general, also record skipping and setting a "saved" variable and then potentially acting on that variable state.

edit: this method is too large. Is it too late to refactor?

Francesco Rodríguez

never is too late, send a pull request :)

fingermark

The code has if autosave && ... on line 342 and elsif autosave != false && ... on line 344. Why not be consistent and change line 344 to elsif autosave && ...?

Please sign in to comment.
Something went wrong with that request. Please try again.