Skip to content

Commit

Permalink
Backport #3329 to 3-2-stable
Browse files Browse the repository at this point in the history
Fix bug with autosave collection association on new record with a marked
for destroy record in autosave collection.

Fixes #6918.
  • Loading branch information
Francesco Rodriguez committed Jul 2, 2012
1 parent 9e0b3fc commit b1e509a
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 15 deletions.
36 changes: 21 additions & 15 deletions activerecord/lib/active_record/autosave_association.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -332,25 +332,31 @@ def save_collection_association(reflection)


if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave) if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
begin begin
records.each do |record| records_to_destroy = []
next if record.destroyed?
records.each do |record|
next if record.destroyed?

This comment has been minimized.

Copy link
@adacosta

adacosta Jul 26, 2012

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?

This comment has been minimized.

Copy link
@frodsan

frodsan Jul 26, 2012

Contributor

never is too late, send a pull request :)


saved = true

if autosave && record.marked_for_destruction?
records_to_destroy << record
elsif autosave != false && (@new_record_before_save || record.new_record?)

This comment has been minimized.

Copy link
@fingermark

fingermark Aug 14, 2012

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 && ...?

if autosave
saved = association.insert_record(record, false)
else
association.insert_record(record) unless reflection.nested?
end
elsif autosave
saved = record.save(:validate => false)
end


saved = true raise ActiveRecord::Rollback unless saved
end


if autosave && record.marked_for_destruction? records_to_destroy.each do |record|
association.proxy.destroy(record) association.proxy.destroy(record)
elsif autosave != false && (@new_record_before_save || record.new_record?)
if autosave
saved = association.insert_record(record, false)
else
association.insert_record(record) unless reflection.nested?
end
elsif autosave
saved = record.save(:validate => false)
end end

raise ActiveRecord::Rollback unless saved
end
rescue rescue
records.each {|x| IdentityMap.remove(x) } if IdentityMap.enabled? records.each {|x| IdentityMap.remove(x) } if IdentityMap.enabled?
raise raise
Expand Down
10 changes: 10 additions & 0 deletions activerecord/test/cases/autosave_association_test.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -770,6 +770,16 @@ def destroy(*args)
assert_equal before, @pirate.reload.birds assert_equal before, @pirate.reload.birds
end end


def test_when_new_record_a_child_marked_for_destruction_should_not_affect_other_records_from_saving
@pirate = @ship.build_pirate(:catchphrase => "Arr' now I shall keep me eye on you matey!") # new record

3.times { |i| @pirate.birds.build(:name => "birds_#{i}") }
@pirate.birds[1].mark_for_destruction
@pirate.save!

assert_equal 2, @pirate.birds.reload.length
end

# Add and remove callbacks tests for association collections. # Add and remove callbacks tests for association collections.
%w{ method proc }.each do |callback_type| %w{ method proc }.each do |callback_type|
define_method("test_should_run_add_callback_#{callback_type}s_for_has_many") do define_method("test_should_run_add_callback_#{callback_type}s_for_has_many") do
Expand Down

0 comments on commit b1e509a

Please sign in to comment.