aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test/cases/autosave_association_test.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/test/cases/autosave_association_test.rb')
-rw-r--r--activerecord/test/cases/autosave_association_test.rb83
1 files changed, 68 insertions, 15 deletions
diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb
index cf763d730a..cc36a6dc5b 100644
--- a/activerecord/test/cases/autosave_association_test.rb
+++ b/activerecord/test/cases/autosave_association_test.rb
@@ -3,6 +3,8 @@ require 'models/bird'
require 'models/company'
require 'models/customer'
require 'models/developer'
+require 'models/invoice'
+require 'models/line_item'
require 'models/order'
require 'models/parrot'
require 'models/person'
@@ -699,23 +701,18 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
define_method("test_should_rollback_destructions_if_an_exception_occurred_while_saving_#{association_name}") do
2.times { |i| @pirate.send(association_name).create!(:name => "#{association_name}_#{i}") }
- before = @pirate.send(association_name).map { |c| c }
+ before = @pirate.send(association_name).map { |c| c.mark_for_destruction ; c }
- # Stub the save method of the first child to destroy and the second to raise an exception
- class << before.first
- def save(*args)
- super
- destroy
- end
- end
+ # Stub the destroy method of the the second child to raise an exception
class << before.last
- def save(*args)
+ def destroy(*args)
super
raise 'Oh noes!'
end
end
assert_raise(RuntimeError) { assert !@pirate.save }
+ assert before.first.frozen? # the first child was indeed destroyed
assert_equal before, @pirate.reload.send(association_name)
end
@@ -797,6 +794,14 @@ class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase
assert @pirate.errors[:catchphrase].any?
end
+ def test_should_not_ignore_different_error_messages_on_the_same_attribute
+ Ship.validates_format_of :name, :with => /\w/
+ @pirate.ship.name = ""
+ @pirate.catchphrase = nil
+ assert @pirate.invalid?
+ assert_equal ["can't be blank", "is invalid"], @pirate.errors[:"ship.name"]
+ end
+
def test_should_still_allow_to_bypass_validations_on_the_associated_model
@pirate.catchphrase = ''
@pirate.ship.name = ''
@@ -833,6 +838,18 @@ class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase
end
end
+ def test_should_not_save_and_return_false_if_a_callback_cancelled_saving
+ pirate = Pirate.new(:catchphrase => 'Arr')
+ ship = pirate.build_ship(:name => 'The Vile Insanity')
+ ship.cancel_save_from_callback = true
+
+ assert_no_difference 'Pirate.count' do
+ assert_no_difference 'Ship.count' do
+ assert !pirate.save
+ end
+ end
+ end
+
def test_should_rollback_any_changes_if_an_exception_occurred_while_saving
before = [@pirate.catchphrase, @pirate.ship.name]
@@ -916,6 +933,18 @@ class TestAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase
end
end
+ def test_should_not_save_and_return_false_if_a_callback_cancelled_saving
+ ship = Ship.new(:name => 'The Vile Insanity')
+ pirate = ship.build_pirate(:catchphrase => 'Arr')
+ pirate.cancel_save_from_callback = true
+
+ assert_no_difference 'Ship.count' do
+ assert_no_difference 'Pirate.count' do
+ assert !ship.save
+ end
+ end
+ end
+
def test_should_rollback_any_changes_if_an_exception_occurred_while_saving
before = [@ship.pirate.catchphrase, @ship.name]
@@ -931,7 +960,6 @@ class TestAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase
end
assert_raise(RuntimeError) { assert !@ship.save }
- # TODO: Why does using reload on @ship looses the associated pirate?
assert_equal before, [@ship.pirate.reload.catchphrase, @ship.reload.name]
end
@@ -974,9 +1002,9 @@ module AutosaveAssociationOnACollectionAssociationTests
end
def test_should_default_invalid_error_from_i18n
- I18n.backend.store_translations(:en, :activerecord => { :errors => { :models =>
+ I18n.backend.store_translations(:en, :errors => { :models =>
{ @association_name.to_s.singularize.to_sym => { :blank => "cannot be blank" } }
- }})
+ })
@pirate.send(@association_name).build(:name => '')
@@ -985,9 +1013,7 @@ module AutosaveAssociationOnACollectionAssociationTests
assert_equal ["#{@association_name.to_s.titleize} name cannot be blank"], @pirate.errors.full_messages
assert @pirate.errors[@association_name].empty?
ensure
- I18n.backend.store_translations(:en, :activerecord => { :errors => { :models =>
- { @association_name.to_s.singularize.to_sym => nil }
- }})
+ I18n.backend = I18n::Backend::Simple.new
end
def test_should_merge_errors_on_the_associated_models_onto_the_parent_even_if_it_is_not_valid
@@ -1034,6 +1060,26 @@ module AutosaveAssociationOnACollectionAssociationTests
end
end
+ def test_should_not_save_and_return_false_if_a_callback_cancelled_saving_in_either_create_or_update
+ @pirate.catchphrase = 'Changed'
+ @child_1.name = 'Changed'
+ @child_1.cancel_save_from_callback = true
+
+ assert !@pirate.save
+ assert_equal "Don' botharrr talkin' like one, savvy?", @pirate.reload.catchphrase
+ assert_equal "Posideons Killer", @child_1.reload.name
+
+ new_pirate = Pirate.new(:catchphrase => 'Arr')
+ new_child = new_pirate.send(@association_name).build(:name => 'Grace OMalley')
+ new_child.cancel_save_from_callback = true
+
+ assert_no_difference 'Pirate.count' do
+ assert_no_difference "#{new_child.class.name}.count" do
+ assert !new_pirate.save
+ end
+ end
+ end
+
def test_should_rollback_any_changes_if_an_exception_occurred_while_saving
before = [@pirate.catchphrase, *@pirate.send(@association_name).map(&:name)]
new_names = ['Grace OMalley', 'Privateers Greed']
@@ -1217,3 +1263,10 @@ class TestAutosaveAssociationValidationMethodsGeneration < ActiveRecord::TestCas
assert !@pirate.respond_to?(:validate_associated_records_for_non_validated_parrots)
end
end
+
+class TestAutosaveAssociationWithTouch < ActiveRecord::TestCase
+ def test_autosave_with_touch_should_not_raise_system_stack_error
+ invoice = Invoice.create
+ assert_nothing_raised { invoice.line_items.create(:amount => 10) }
+ end
+end