Skip to content

Instantly share code, notes, and snippets.

@spastorino
Created November 8, 2010 21:54
Show Gist options
  • Save spastorino/668338 to your computer and use it in GitHub Desktop.
Save spastorino/668338 to your computer and use it in GitHub Desktop.
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index 65434fb..829299a 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -224,9 +224,9 @@ module ActiveRecord
# # creates avatar_attributes= and posts_attributes=
# accepts_nested_attributes_for :avatar, :posts, :allow_destroy => true
def accepts_nested_attributes_for(*attr_names)
- options = { :allow_destroy => false, :update_only => false }
+ options = { :allow_destroy => false, :update_only => false, :partial_updates => false }
options.update(attr_names.extract_options!)
- options.assert_valid_keys(:allow_destroy, :reject_if, :limit, :update_only)
+ options.assert_valid_keys(:allow_destroy, :reject_if, :limit, :update_only, :partial_updates)
options[:reject_if] = REJECT_ALL_BLANK_PROC if options[:reject_if] == :all_blank
attr_names.each do |association_name|
@@ -342,12 +342,16 @@ module ActiveRecord
association = send(association_name)
- existing_records = if association.loaded?
- association.to_a
- else
- attribute_ids = attributes_collection.map {|a| a['id'] || a[:id] }.compact
- attribute_ids.present? ? association.all(:conditions => {association.primary_key => attribute_ids}) : []
- end
+ existing_records = if options[:partial_updates]
+ if association.loaded?
+ association.to_a
+ else
+ attribute_ids = attributes_collection.map {|a| a['id'] || a[:id] }.compact
+ attribute_ids.present? ? association.all(:conditions => {association.primary_key => attribute_ids}) : []
+ end
+ else
+ association
+ end
attributes_collection.each do |attributes|
attributes = attributes.with_indifferent_access
@@ -357,7 +361,7 @@ module ActiveRecord
association.build(attributes.except(*UNASSIGNABLE_KEYS))
end
elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes['id'].to_s }
- association.send(:add_record_to_target_with_callbacks, existing_record) unless association.loaded?
+ association.send(:add_record_to_target_with_callbacks, existing_record) if !association.loaded? && options[:partial_updates]
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
else
raise_nested_attributes_record_not_found(association_name, attributes['id'])
diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb
index 3adcc88..b73f231 100644
--- a/activerecord/test/cases/nested_attributes_test.rb
+++ b/activerecord/test/cases/nested_attributes_test.rb
@@ -456,13 +456,16 @@ module NestedAttributesOnACollectionAssociationTests
end
def test_should_not_load_association_when_updating_existing_records
- @pirate.reload
- @pirate.send(association_setter, [{ :id => @child_1.id, :name => 'Grace OMalley' }])
- assert ! @pirate.send(@association_name).loaded?
+ Man.accepts_nested_attributes_for(:interests, :partial_updates => true)
+ Man.create(:name => 'John',
+ :interests_attributes => [{:topic=>'Cars'}])
+ m = Man.last
+ m.interests_attributes = [{:id => m.interests.last.id, :topic=>'Trucks'}]
+ assert ! m.interests.loaded?
- @pirate.save
- assert ! @pirate.send(@association_name).loaded?
- assert_equal 'Grace OMalley', @child_1.reload.name
+ m.save
+ assert ! m.interests.loaded?
+ assert_equal 'Trucks', m.interests.last.reload.topic
end
def test_should_not_overwrite_unsaved_updates_when_loading_association
@@ -652,6 +655,17 @@ module NestedAttributesOnACollectionAssociationTests
Interest.reflect_on_association(:man).options[:inverse_of] = :interests
end
+ def test_validate_presence_of_parent_fails_if_son_fails_without_reloading
+ Man.accepts_nested_attributes_for(:interests)
+ Interest.validates_presence_of(:topic)
+ Man.create(:name => 'John',
+ :interests_attributes => [{:topic=>'Cars'}])
+ m = Man.last
+ m.interests_attributes = [{:id => m.interests.last.id, :topic=>''}]
+ assert !m.interests.last.valid?
+ assert !m.valid?
+ end
+
private
def association_setter
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment