From 9550916903c931161f04a98091fba712d7fa5c1d Mon Sep 17 00:00:00 2001 From: Eloy Duran Date: Sun, 3 Jan 2010 22:48:25 +0100 Subject: Raise a RecordNotFound if an ID in nested attributes is given but doesn't return a record. [#2415 state:resolved] --- .../lib/active_record/nested_attributes.rb | 11 ++++++++++ activerecord/test/cases/nested_attributes_test.rb | 24 ++++++++++++++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index e1e80355c0..9038888d22 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -288,6 +288,10 @@ module ActiveRecord if check_existing_record && (record = send(association_name)) && (options[:update_only] || record.id.to_s == attributes['id'].to_s) assign_to_or_mark_for_destruction(record, attributes, options[:allow_destroy]) + + elsif attributes['id'] + raise_nested_attributes_record_not_found(association_name, attributes['id']) + elsif !reject_new_record?(association_name, attributes) method = "build_#{association_name}" if respond_to?(method) @@ -349,6 +353,8 @@ module ActiveRecord end elsif existing_record = send(association_name).detect { |record| record.id.to_s == attributes['id'].to_s } assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy]) + else + raise_nested_attributes_record_not_found(association_name, attributes['id']) end end end @@ -383,5 +389,10 @@ module ActiveRecord callback.call(attributes) end end + + def raise_nested_attributes_record_not_found(association_name, record_id) + reflection = self.class.reflect_on_association(association_name) + raise RecordNotFound, "Couldn't find #{reflection.klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}" + end end end diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index d034bf23a0..7ca9c416cb 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -173,6 +173,12 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name end + def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record + assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find Ship with ID=1234567890 for Pirate with ID=#{@pirate.id}" do + @pirate.ship_attributes = { :id => 1234567890 } + end + end + def test_should_take_a_hash_with_string_keys_and_update_the_associated_model @pirate.reload.ship_attributes = { 'id' => @ship.id, 'name' => 'Davy Jones Gold Dagger' } @@ -266,6 +272,8 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase end class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase + include AssertRaiseWithMessage + def setup @ship = Ship.new(:name => 'Nights Dirty Lightning') @pirate = @ship.build_pirate(:catchphrase => 'Aye') @@ -320,6 +328,12 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase assert_equal 'Arr', @ship.pirate.catchphrase end + def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record + assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find Pirate with ID=1234567890 for Ship with ID=#{@ship.id}" do + @ship.pirate_attributes = { :id => 1234567890 } + end + end + def test_should_take_a_hash_with_string_keys_and_update_the_associated_model @ship.reload.pirate_attributes = { 'id' => @pirate.id, 'catchphrase' => 'Arr' } @@ -381,10 +395,6 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase assert Ship.reflect_on_association(:pirate).options[:autosave] end - def test_should_accept_update_only_option - @ship.update_attribute(:update_only_pirate_attributes, { :id => @pirate.ship.id, :catchphrase => 'Arr' }) - end - def test_should_create_new_model_when_nothing_is_there_and_update_only_is_true @pirate.delete assert_difference('Pirate.count', 1) do @@ -457,6 +467,12 @@ module NestedAttributesOnACollectionAssociationTests assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.name, @child_2.name] end + def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record + assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find #{@child_1.class.name} with ID=1234567890 for Pirate with ID=#{@pirate.id}" do + @pirate.attributes = { association_getter => [{ :id => 1234567890 }] } + end + end + def test_should_automatically_build_new_associated_models_for_each_entry_in_a_hash_where_the_id_is_missing @pirate.send(@association_name).destroy_all @pirate.reload.attributes = { -- cgit v1.2.3