3
require 'models/company'
4
require 'models/customer'
5
require 'models/developer'
7
require 'models/parrot'
8
require 'models/person'
9
require 'models/pirate'
11
require 'models/reader'
13
require 'models/ship_part'
14
require 'models/treasure'
16
class TestAutosaveAssociationsInGeneral < ActiveRecord::TestCase
17
def test_autosave_should_be_a_valid_option_for_has_one
18
assert base.valid_keys_for_has_one_association.include?(:autosave)
21
def test_autosave_should_be_a_valid_option_for_belongs_to
22
assert base.valid_keys_for_belongs_to_association.include?(:autosave)
25
def test_autosave_should_be_a_valid_option_for_has_many
26
assert base.valid_keys_for_has_many_association.include?(:autosave)
29
def test_autosave_should_be_a_valid_option_for_has_and_belongs_to_many
30
assert base.valid_keys_for_has_and_belongs_to_many_association.include?(:autosave)
40
class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase
41
def test_should_save_parent_but_not_invalid_child
42
firm = Firm.new(:name => 'GlobalMegaCorp')
45
firm.build_account_using_primary_key
46
assert !firm.build_account_using_primary_key.valid?
49
assert firm.account_using_primary_key.new_record?
52
def test_save_fails_for_invalid_has_one
53
firm = Firm.find(:first)
56
firm.account = Account.new
58
assert !firm.account.valid?
61
assert_equal "is invalid", firm.errors.on("account")
64
def test_save_succeeds_for_invalid_has_one_with_validate_false
65
firm = Firm.find(:first)
68
firm.unvalidated_account = Account.new
70
assert !firm.unvalidated_account.valid?
75
def test_build_before_child_saved
78
account = firm.account.build("credit_limit" => 1000)
79
assert_equal account, firm.account
80
assert account.new_record?
82
assert_equal account, firm.account
83
assert !account.new_record?
86
def test_build_before_either_saved
87
firm = Firm.new("name" => "GlobalMegaCorp")
89
firm.account = account = Account.new("credit_limit" => 1000)
90
assert_equal account, firm.account
91
assert account.new_record?
93
assert_equal account, firm.account
94
assert !account.new_record?
97
def test_assignment_before_parent_saved
98
firm = Firm.new("name" => "GlobalMegaCorp")
99
firm.account = a = Account.find(1)
100
assert firm.new_record?
101
assert_equal a, firm.account
103
assert_equal a, firm.account
104
assert_equal a, firm.account(true)
107
def test_assignment_before_either_saved
108
firm = Firm.new("name" => "GlobalMegaCorp")
109
firm.account = a = Account.new("credit_limit" => 1000)
110
assert firm.new_record?
112
assert_equal a, firm.account
114
assert !firm.new_record?
115
assert !a.new_record?
116
assert_equal a, firm.account
117
assert_equal a, firm.account(true)
120
def test_not_resaved_when_unchanged
121
firm = Firm.find(:first, :include => :account)
122
firm.name += '-changed'
123
assert_queries(1) { firm.save! }
125
firm = Firm.find(:first)
126
firm.account = Account.find(:first)
127
assert_queries(Firm.partial_updates? ? 0 : 1) { firm.save! }
129
firm = Firm.find(:first).clone
130
firm.account = Account.find(:first)
131
assert_queries(2) { firm.save! }
133
firm = Firm.find(:first).clone
134
firm.account = Account.find(:first).clone
135
assert_queries(2) { firm.save! }
139
class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase
140
def test_should_save_parent_but_not_invalid_child
141
client = Client.new(:name => 'Joe (the Plumber)')
145
assert !client.firm.valid?
148
assert client.firm.new_record?
151
def test_save_fails_for_invalid_belongs_to
152
assert log = AuditLog.create(:developer_id => 0, :message => "")
154
log.developer = Developer.new
155
assert !log.developer.valid?
158
assert_equal "is invalid", log.errors.on("developer")
161
def test_save_succeeds_for_invalid_belongs_to_with_validate_false
162
assert log = AuditLog.create(:developer_id => 0, :message=> "")
164
log.unvalidated_developer = Developer.new
165
assert !log.unvalidated_developer.valid?
170
def test_assignment_before_parent_saved
171
client = Client.find(:first)
172
apple = Firm.new("name" => "Apple")
174
assert_equal apple, client.firm
175
assert apple.new_record?
178
assert !apple.new_record?
179
assert_equal apple, client.firm
180
assert_equal apple, client.firm(true)
183
def test_assignment_before_either_saved
184
final_cut = Client.new("name" => "Final Cut")
185
apple = Firm.new("name" => "Apple")
186
final_cut.firm = apple
187
assert final_cut.new_record?
188
assert apple.new_record?
189
assert final_cut.save
190
assert !final_cut.new_record?
191
assert !apple.new_record?
192
assert_equal apple, final_cut.firm
193
assert_equal apple, final_cut.firm(true)
196
def test_store_two_association_with_one_save
197
num_orders = Order.count
198
num_customers = Customer.count
201
customer1 = order.billing = Customer.new
202
customer2 = order.shipping = Customer.new
204
assert_equal customer1, order.billing
205
assert_equal customer2, order.shipping
209
assert_equal customer1, order.billing
210
assert_equal customer2, order.shipping
212
assert_equal num_orders +1, Order.count
213
assert_equal num_customers +2, Customer.count
216
def test_store_association_in_two_relations_with_one_save
217
num_orders = Order.count
218
num_customers = Customer.count
221
customer = order.billing = order.shipping = Customer.new
223
assert_equal customer, order.billing
224
assert_equal customer, order.shipping
228
assert_equal customer, order.billing
229
assert_equal customer, order.shipping
231
assert_equal num_orders +1, Order.count
232
assert_equal num_customers +1, Customer.count
235
def test_store_association_in_two_relations_with_one_save_in_existing_object
236
num_orders = Order.count
237
num_customers = Customer.count
240
customer = order.billing = order.shipping = Customer.new
242
assert_equal customer, order.billing
243
assert_equal customer, order.shipping
247
assert_equal customer, order.billing
248
assert_equal customer, order.shipping
250
assert_equal num_orders +1, Order.count
251
assert_equal num_customers +1, Customer.count
254
def test_store_association_in_two_relations_with_one_save_in_existing_object_with_values
255
num_orders = Order.count
256
num_customers = Customer.count
259
customer = order.billing = order.shipping = Customer.new
261
assert_equal customer, order.billing
262
assert_equal customer, order.shipping
266
customer = order.billing = order.shipping = Customer.new
271
assert_equal customer, order.billing
272
assert_equal customer, order.shipping
274
assert_equal num_orders +1, Order.count
275
assert_equal num_customers +2, Customer.count
279
class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCase
280
fixtures :companies, :people
282
def test_invalid_adding
284
assert !(firm.clients_of_firm << c = Client.new)
291
def test_invalid_adding_before_save
292
no_of_firms = Firm.count
293
no_of_clients = Client.count
294
new_firm = Firm.new("name" => "A New Firm, Inc")
295
new_firm.clients_of_firm.concat([c = Client.new, Client.new("name" => "Apple")])
298
assert !new_firm.valid?
299
assert !new_firm.save
301
assert new_firm.new_record?
304
def test_invalid_adding_with_validate_false
305
firm = Firm.find(:first)
307
firm.unvalidated_clients_of_firm << client
310
assert !client.valid?
312
assert client.new_record?
315
def test_valid_adding_with_validate_false
316
no_of_clients = Client.count
318
firm = Firm.find(:first)
319
client = Client.new("name" => "Apple")
323
assert client.new_record?
325
firm.unvalidated_clients_of_firm << client
328
assert !client.new_record?
329
assert_equal no_of_clients+1, Client.count
332
def test_invalid_build
333
new_client = companies(:first_firm).clients_of_firm.build
334
assert new_client.new_record?
335
assert !new_client.valid?
336
assert_equal new_client, companies(:first_firm).clients_of_firm.last
337
assert !companies(:first_firm).save
338
assert new_client.new_record?
339
assert_equal 1, companies(:first_firm).clients_of_firm(true).size
342
def test_adding_before_save
343
no_of_firms = Firm.count
344
no_of_clients = Client.count
346
new_firm = Firm.new("name" => "A New Firm, Inc")
347
c = Client.new("name" => "Apple")
349
new_firm.clients_of_firm.push Client.new("name" => "Natural Company")
350
assert_equal 1, new_firm.clients_of_firm.size
351
new_firm.clients_of_firm << c
352
assert_equal 2, new_firm.clients_of_firm.size
354
assert_equal no_of_firms, Firm.count # Firm was not saved to database.
355
assert_equal no_of_clients, Client.count # Clients were not saved to database.
357
assert !new_firm.new_record?
358
assert !c.new_record?
359
assert_equal new_firm, c.firm
360
assert_equal no_of_firms+1, Firm.count # Firm was saved to database.
361
assert_equal no_of_clients+2, Client.count # Clients were saved to database.
363
assert_equal 2, new_firm.clients_of_firm.size
364
assert_equal 2, new_firm.clients_of_firm(true).size
368
firm = Firm.new("name" => "Apple")
369
firm.client_ids = [companies(:first_client).id, companies(:second_client).id]
372
assert_equal 2, firm.clients.length
373
assert firm.clients.include?(companies(:second_client))
376
def test_assign_ids_for_through_a_belongs_to
377
post = Post.new(:title => "Assigning IDs works!", :body => "You heared it here first, folks!")
378
post.person_ids = [people(:david).id, people(:michael).id]
381
assert_equal 2, post.people.length
382
assert post.people.include?(people(:david))
385
def test_build_before_save
386
company = companies(:first_firm)
387
new_client = assert_no_queries { company.clients_of_firm.build("name" => "Another Client") }
388
assert !company.clients_of_firm.loaded?
390
company.name += '-changed'
391
assert_queries(2) { assert company.save }
392
assert !new_client.new_record?
393
assert_equal 2, company.clients_of_firm(true).size
396
def test_build_many_before_save
397
company = companies(:first_firm)
398
new_clients = assert_no_queries { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) }
400
company.name += '-changed'
401
assert_queries(3) { assert company.save }
402
assert_equal 3, company.clients_of_firm(true).size
405
def test_build_via_block_before_save
406
company = companies(:first_firm)
407
new_client = assert_no_queries { company.clients_of_firm.build {|client| client.name = "Another Client" } }
408
assert !company.clients_of_firm.loaded?
410
company.name += '-changed'
411
assert_queries(2) { assert company.save }
412
assert !new_client.new_record?
413
assert_equal 2, company.clients_of_firm(true).size
416
def test_build_many_via_block_before_save
417
company = companies(:first_firm)
418
new_clients = assert_no_queries do
419
company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) do |client|
420
client.name = "changed"
424
company.name += '-changed'
425
assert_queries(3) { assert company.save }
426
assert_equal 3, company.clients_of_firm(true).size
429
def test_replace_on_new_object
430
firm = Firm.new("name" => "New Firm")
431
firm.clients = [companies(:second_client), Client.new("name" => "New Client")]
434
assert_equal 2, firm.clients.length
435
assert firm.clients.include?(Client.find_by_name("New Client"))
439
class TestDefaultAutosaveAssociationOnNewRecord < ActiveRecord::TestCase
440
def test_autosave_new_record_on_belongs_to_can_be_disabled_per_relationship
441
new_account = Account.new("credit_limit" => 1000)
442
new_firm = Firm.new("name" => "some firm")
444
assert new_firm.new_record?
445
new_account.firm = new_firm
448
assert !new_firm.new_record?
450
new_account = Account.new("credit_limit" => 1000)
451
new_autosaved_firm = Firm.new("name" => "some firm")
453
assert new_autosaved_firm.new_record?
454
new_account.unautosaved_firm = new_autosaved_firm
457
assert new_autosaved_firm.new_record?
460
def test_autosave_new_record_on_has_one_can_be_disabled_per_relationship
461
firm = Firm.new("name" => "some firm")
462
account = Account.new("credit_limit" => 1000)
464
assert account.new_record?
465
firm.account = account
468
assert !account.new_record?
470
firm = Firm.new("name" => "some firm")
471
account = Account.new("credit_limit" => 1000)
473
firm.unautosaved_account = account
475
assert account.new_record?
476
firm.unautosaved_account = account
479
assert account.new_record?
482
def test_autosave_new_record_on_has_many_can_be_disabled_per_relationship
483
firm = Firm.new("name" => "some firm")
484
account = Account.new("credit_limit" => 1000)
486
assert account.new_record?
487
firm.accounts << account
490
assert !account.new_record?
492
firm = Firm.new("name" => "some firm")
493
account = Account.new("credit_limit" => 1000)
495
assert account.new_record?
496
firm.unautosaved_accounts << account
499
assert account.new_record?
503
class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
504
self.use_transactional_fixtures = false
507
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
508
@ship = @pirate.create_ship(:name => 'Nights Dirty Lightning')
512
def test_a_marked_for_destruction_record_should_not_be_be_marked_after_reload
513
@pirate.mark_for_destruction
514
@pirate.ship.mark_for_destruction
516
assert !@pirate.reload.marked_for_destruction?
517
assert !@pirate.ship.marked_for_destruction?
521
def test_should_destroy_a_child_association_as_part_of_the_save_transaction_if_it_was_marked_for_destroyal
522
assert !@pirate.ship.marked_for_destruction?
524
@pirate.ship.mark_for_destruction
527
assert @pirate.ship.marked_for_destruction?
528
assert Ship.find_by_id(id)
531
assert_nil @pirate.reload.ship
532
assert_nil Ship.find_by_id(id)
535
def test_should_skip_validation_on_a_child_association_if_marked_for_destruction
536
@pirate.ship.name = ''
537
assert !@pirate.valid?
539
@pirate.ship.mark_for_destruction
540
@pirate.ship.expects(:valid?).never
541
assert_difference('Ship.count', -1) { @pirate.save! }
544
def test_a_child_marked_for_destruction_should_not_be_destroyed_twice
545
@pirate.ship.mark_for_destruction
547
@pirate.ship.expects(:destroy).never
551
def test_should_rollback_destructions_if_an_exception_occurred_while_saving_a_child
552
# Stub the save method of the @pirate.ship instance to destroy and then raise an exception
553
class << @pirate.ship
561
assert_raise(RuntimeError) { assert !@pirate.save }
562
assert_not_nil @pirate.reload.ship
566
def test_should_destroy_a_parent_association_as_part_of_the_save_transaction_if_it_was_marked_for_destroyal
567
assert !@ship.pirate.marked_for_destruction?
569
@ship.pirate.mark_for_destruction
572
assert @ship.pirate.marked_for_destruction?
573
assert Pirate.find_by_id(id)
576
assert_nil @ship.reload.pirate
577
assert_nil Pirate.find_by_id(id)
580
def test_should_skip_validation_on_a_parent_association_if_marked_for_destruction
581
@ship.pirate.catchphrase = ''
584
@ship.pirate.mark_for_destruction
585
@ship.pirate.expects(:valid?).never
586
assert_difference('Pirate.count', -1) { @ship.save! }
589
def test_a_parent_marked_for_destruction_should_not_be_destroyed_twice
590
@ship.pirate.mark_for_destruction
592
@ship.pirate.expects(:destroy).never
596
def test_should_rollback_destructions_if_an_exception_occurred_while_saving_a_parent
597
# Stub the save method of the @ship.pirate instance to destroy and then raise an exception
598
class << @ship.pirate
606
assert_raise(RuntimeError) { assert !@ship.save }
607
assert_not_nil @ship.reload.pirate
610
# has_many & has_and_belongs_to
611
%w{ parrots birds }.each do |association_name|
612
define_method("test_should_destroy_#{association_name}_as_part_of_the_save_transaction_if_they_were_marked_for_destroyal") do
613
2.times { |i| @pirate.send(association_name).create!(:name => "#{association_name}_#{i}") }
615
assert !@pirate.send(association_name).any? { |child| child.marked_for_destruction? }
617
@pirate.send(association_name).each { |child| child.mark_for_destruction }
618
klass = @pirate.send(association_name).first.class
619
ids = @pirate.send(association_name).map(&:id)
621
assert @pirate.send(association_name).all? { |child| child.marked_for_destruction? }
622
ids.each { |id| assert klass.find_by_id(id) }
625
assert @pirate.reload.send(association_name).empty?
626
ids.each { |id| assert_nil klass.find_by_id(id) }
629
define_method("test_should_skip_validation_on_the_#{association_name}_association_if_marked_for_destruction") do
630
2.times { |i| @pirate.send(association_name).create!(:name => "#{association_name}_#{i}") }
631
children = @pirate.send(association_name)
633
children.each { |child| child.name = '' }
634
assert !@pirate.valid?
636
children.each do |child|
637
child.mark_for_destruction
638
child.expects(:valid?).never
640
assert_difference("#{association_name.classify}.count", -2) { @pirate.save! }
643
define_method("test_should_skip_validation_on_the_#{association_name}_association_if_destroyed") do
644
@pirate.send(association_name).create!(:name => "#{association_name}_1")
645
children = @pirate.send(association_name)
647
children.each { |child| child.name = '' }
648
assert !@pirate.valid?
650
children.each { |child| child.destroy }
651
assert @pirate.valid?
654
define_method("test_a_child_marked_for_destruction_should_not_be_destroyed_twice_while_saving_#{association_name}") do
655
@pirate.send(association_name).create!(:name => "#{association_name}_1")
656
children = @pirate.send(association_name)
658
children.each { |child| child.mark_for_destruction }
660
children.each { |child| child.expects(:destroy).never }
664
define_method("test_should_rollback_destructions_if_an_exception_occurred_while_saving_#{association_name}") do
665
2.times { |i| @pirate.send(association_name).create!(:name => "#{association_name}_#{i}") }
666
before = @pirate.send(association_name).map { |c| c }
668
# Stub the save method of the first child to destroy and the second to raise an exception
669
class << before.first
682
assert_raise(RuntimeError) { assert !@pirate.save }
683
assert_equal before, @pirate.reload.send(association_name)
686
# Add and remove callbacks tests for association collections.
687
%w{ method proc }.each do |callback_type|
688
define_method("test_should_run_add_callback_#{callback_type}s_for_#{association_name}") do
689
association_name_with_callbacks = "#{association_name}_with_#{callback_type}_callbacks"
691
pirate = Pirate.new(:catchphrase => "Arr")
692
pirate.send(association_name_with_callbacks).build(:name => "Crowe the One-Eyed")
695
"before_adding_#{callback_type}_#{association_name.singularize}_<new>",
696
"after_adding_#{callback_type}_#{association_name.singularize}_<new>"
699
assert_equal expected, pirate.ship_log
702
define_method("test_should_run_remove_callback_#{callback_type}s_for_#{association_name}") do
703
association_name_with_callbacks = "#{association_name}_with_#{callback_type}_callbacks"
705
@pirate.send(association_name_with_callbacks).create!(:name => "Crowe the One-Eyed")
706
@pirate.send(association_name_with_callbacks).each { |c| c.mark_for_destruction }
707
child_id = @pirate.send(association_name_with_callbacks).first.id
709
@pirate.ship_log.clear
713
"before_removing_#{callback_type}_#{association_name.singularize}_#{child_id}",
714
"after_removing_#{callback_type}_#{association_name.singularize}_#{child_id}"
717
assert_equal expected, @pirate.ship_log
723
class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase
724
self.use_transactional_fixtures = false
727
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
728
@ship = @pirate.create_ship(:name => 'Nights Dirty Lightning')
731
def test_should_still_work_without_an_associated_model
733
@pirate.reload.catchphrase = "Arr"
735
assert 'Arr', @pirate.reload.catchphrase
738
def test_should_automatically_save_the_associated_model
739
@pirate.ship.name = 'The Vile Insanity'
741
assert_equal 'The Vile Insanity', @pirate.reload.ship.name
744
def test_should_automatically_save_bang_the_associated_model
745
@pirate.ship.name = 'The Vile Insanity'
747
assert_equal 'The Vile Insanity', @pirate.reload.ship.name
750
def test_should_automatically_validate_the_associated_model
751
@pirate.ship.name = ''
752
assert !@pirate.valid?
753
assert_equal "can't be blank", @pirate.errors.on(:"ship.name")
756
def test_should_merge_errors_on_the_associated_models_onto_the_parent_even_if_it_is_not_valid
757
@pirate.ship.name = nil
758
@pirate.catchphrase = nil
759
assert !@pirate.valid?
760
assert @pirate.errors.full_messages.include?("Name can't be blank")
761
assert @pirate.errors.full_messages.include?("Catchphrase can't be blank")
764
def test_should_still_allow_to_bypass_validations_on_the_associated_model
765
@pirate.catchphrase = ''
766
@pirate.ship.name = ''
768
assert_equal ['', ''], [@pirate.reload.catchphrase, @pirate.ship.name]
771
def test_should_allow_to_bypass_validations_on_associated_models_at_any_depth
772
2.times { |i| @pirate.ship.parts.create!(:name => "part #{i}") }
774
@pirate.catchphrase = ''
775
@pirate.ship.name = ''
776
@pirate.ship.parts.each { |part| part.name = '' }
779
values = [@pirate.reload.catchphrase, @pirate.ship.name, *@pirate.ship.parts.map(&:name)]
780
assert_equal ['', '', '', ''], values
783
def test_should_still_raise_an_ActiveRecordRecord_Invalid_exception_if_we_want_that
784
@pirate.ship.name = ''
785
assert_raise(ActiveRecord::RecordInvalid) do
790
def test_should_rollback_any_changes_if_an_exception_occurred_while_saving
791
before = [@pirate.catchphrase, @pirate.ship.name]
793
@pirate.catchphrase = 'Arr'
794
@pirate.ship.name = 'The Vile Insanity'
796
# Stub the save method of the @pirate.ship instance to raise an exception
797
class << @pirate.ship
804
assert_raise(RuntimeError) { assert !@pirate.save }
805
assert_equal before, [@pirate.reload.catchphrase, @pirate.ship.name]
808
def test_should_not_load_the_associated_model
809
assert_queries(1) { @pirate.catchphrase = 'Arr'; @pirate.save! }
813
class TestAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase
814
self.use_transactional_fixtures = false
817
@ship = Ship.create(:name => 'Nights Dirty Lightning')
818
@pirate = @ship.create_pirate(:catchphrase => "Don' botharrr talkin' like one, savvy?")
821
def test_should_still_work_without_an_associated_model
823
@ship.reload.name = "The Vile Insanity"
825
assert 'The Vile Insanity', @ship.reload.name
828
def test_should_automatically_save_the_associated_model
829
@ship.pirate.catchphrase = 'Arr'
831
assert_equal 'Arr', @ship.reload.pirate.catchphrase
834
def test_should_automatically_save_bang_the_associated_model
835
@ship.pirate.catchphrase = 'Arr'
837
assert_equal 'Arr', @ship.reload.pirate.catchphrase
840
def test_should_automatically_validate_the_associated_model
841
@ship.pirate.catchphrase = ''
843
assert_equal "can't be blank", @ship.errors.on(:"pirate.catchphrase")
846
def test_should_merge_errors_on_the_associated_model_onto_the_parent_even_if_it_is_not_valid
848
@ship.pirate.catchphrase = nil
850
assert @ship.errors.full_messages.include?("Name can't be blank")
851
assert @ship.errors.full_messages.include?("Catchphrase can't be blank")
854
def test_should_still_allow_to_bypass_validations_on_the_associated_model
855
@ship.pirate.catchphrase = ''
858
assert_equal ['', ''], [@ship.reload.name, @ship.pirate.catchphrase]
861
def test_should_still_raise_an_ActiveRecordRecord_Invalid_exception_if_we_want_that
862
@ship.pirate.catchphrase = ''
863
assert_raise(ActiveRecord::RecordInvalid) do
868
def test_should_rollback_any_changes_if_an_exception_occurred_while_saving
869
before = [@ship.pirate.catchphrase, @ship.name]
871
@ship.pirate.catchphrase = 'Arr'
872
@ship.name = 'The Vile Insanity'
874
# Stub the save method of the @ship.pirate instance to raise an exception
875
class << @ship.pirate
882
assert_raise(RuntimeError) { assert !@ship.save }
883
# TODO: Why does using reload on @ship looses the associated pirate?
884
assert_equal before, [@ship.pirate.reload.catchphrase, @ship.reload.name]
887
def test_should_not_load_the_associated_model
888
assert_queries(1) { @ship.name = 'The Vile Insanity'; @ship.save! }
892
module AutosaveAssociationOnACollectionAssociationTests
893
def test_should_automatically_save_the_associated_models
894
new_names = ['Grace OMalley', 'Privateers Greed']
895
@pirate.send(@association_name).each_with_index { |child, i| child.name = new_names[i] }
898
assert_equal new_names, @pirate.reload.send(@association_name).map(&:name)
901
def test_should_automatically_save_bang_the_associated_models
902
new_names = ['Grace OMalley', 'Privateers Greed']
903
@pirate.send(@association_name).each_with_index { |child, i| child.name = new_names[i] }
906
assert_equal new_names, @pirate.reload.send(@association_name).map(&:name)
909
def test_should_automatically_validate_the_associated_models
910
@pirate.send(@association_name).each { |child| child.name = '' }
912
assert !@pirate.valid?
913
assert @pirate.errors.full_messages.include?("Name can't be blank")
914
assert @pirate.errors.on(@association_name).blank?
917
def test_should_not_use_default_invalid_error_on_associated_models
918
@pirate.send(@association_name).build(:name => '')
920
assert !@pirate.valid?
921
assert_equal "can't be blank", @pirate.errors.on("#{@association_name}.name")
922
assert @pirate.errors.on(@association_name).blank?
925
def test_should_merge_errors_on_the_associated_models_onto_the_parent_even_if_it_is_not_valid
926
@pirate.send(@association_name).each { |child| child.name = '' }
927
@pirate.catchphrase = nil
929
assert !@pirate.valid?
930
assert_equal "can't be blank", @pirate.errors.on("#{@association_name}.name")
931
assert !@pirate.errors.on(:catchphrase).blank?
934
def test_should_allow_to_bypass_validations_on_the_associated_models_on_update
935
@pirate.catchphrase = ''
936
@pirate.send(@association_name).each { |child| child.name = '' }
938
assert @pirate.save(false)
939
assert_equal ['', '', ''], [
940
@pirate.reload.catchphrase,
941
@pirate.send(@association_name).first.name,
942
@pirate.send(@association_name).last.name
946
def test_should_validation_the_associated_models_on_create
947
assert_no_difference("#{ @association_name == :birds ? 'Bird' : 'Parrot' }.count") do
948
2.times { @pirate.send(@association_name).build }
953
def test_should_allow_to_bypass_validations_on_the_associated_models_on_create
954
assert_difference("#{ @association_name == :birds ? 'Bird' : 'Parrot' }.count", +2) do
955
2.times { @pirate.send(@association_name).build }
960
def test_should_rollback_any_changes_if_an_exception_occurred_while_saving
961
before = [@pirate.catchphrase, *@pirate.send(@association_name).map(&:name)]
962
new_names = ['Grace OMalley', 'Privateers Greed']
964
@pirate.catchphrase = 'Arr'
965
@pirate.send(@association_name).each_with_index { |child, i| child.name = new_names[i] }
967
# Stub the save method of the first child instance to raise an exception
968
class << @pirate.send(@association_name).first
975
assert_raise(RuntimeError) { assert !@pirate.save }
976
assert_equal before, [@pirate.reload.catchphrase, *@pirate.send(@association_name).map(&:name)]
979
def test_should_still_raise_an_ActiveRecordRecord_Invalid_exception_if_we_want_that
980
@pirate.send(@association_name).each { |child| child.name = '' }
981
assert_raise(ActiveRecord::RecordInvalid) do
986
def test_should_not_load_the_associated_models_if_they_were_not_loaded_yet
987
assert_queries(1) { @pirate.catchphrase = 'Arr'; @pirate.save! }
989
@pirate.send(@association_name).class # hack to load the target
992
@pirate.catchphrase = 'Yarr'
993
new_names = ['Grace OMalley', 'Privateers Greed']
994
@pirate.send(@association_name).each_with_index { |child, i| child.name = new_names[i] }
1000
class TestAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCase
1001
self.use_transactional_fixtures = false
1004
@association_name = :birds
1006
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
1007
@child_1 = @pirate.birds.create(:name => 'Posideons Killer')
1008
@child_2 = @pirate.birds.create(:name => 'Killer bandita Dionne')
1011
include AutosaveAssociationOnACollectionAssociationTests
1014
class TestAutosaveAssociationOnAHasAndBelongsToManyAssociation < ActiveRecord::TestCase
1015
self.use_transactional_fixtures = false
1018
@association_name = :parrots
1021
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
1022
@child_1 = @pirate.parrots.create(:name => 'Posideons Killer')
1023
@child_2 = @pirate.parrots.create(:name => 'Killer bandita Dionne')
1026
include AutosaveAssociationOnACollectionAssociationTests
1029
class TestAutosaveAssociationValidationsOnAHasManyAssocication < ActiveRecord::TestCase
1030
self.use_transactional_fixtures = false
1033
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
1034
@pirate.birds.create(:name => 'cookoo')
1037
test "should automatically validate associations" do
1038
assert @pirate.valid?
1039
@pirate.birds.each { |bird| bird.name = '' }
1041
assert !@pirate.valid?
1045
class TestAutosaveAssociationValidationsOnAHasOneAssocication < ActiveRecord::TestCase
1046
self.use_transactional_fixtures = false
1049
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
1050
@pirate.create_ship(:name => 'titanic')
1053
test "should automatically validate associations with :validate => true" do
1054
assert @pirate.valid?
1055
@pirate.ship.name = ''
1056
assert !@pirate.valid?
1059
test "should not automatically validate associations without :validate => true" do
1060
assert @pirate.valid?
1061
@pirate.non_validated_ship.name = ''
1062
assert @pirate.valid?
1066
class TestAutosaveAssociationValidationsOnABelongsToAssocication < ActiveRecord::TestCase
1067
self.use_transactional_fixtures = false
1070
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
1073
test "should automatically validate associations with :validate => true" do
1074
assert @pirate.valid?
1075
@pirate.parrot = Parrot.new(:name => '')
1076
assert !@pirate.valid?
1079
test "should not automatically validate associations without :validate => true" do
1080
assert @pirate.valid?
1081
@pirate.non_validated_parrot = Parrot.new(:name => '')
1082
assert @pirate.valid?
1086
class TestAutosaveAssociationValidationsOnAHABTMAssocication < ActiveRecord::TestCase
1087
self.use_transactional_fixtures = false
1090
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
1093
test "should automatically validate associations with :validate => true" do
1094
assert @pirate.valid?
1095
@pirate.parrots = [ Parrot.new(:name => 'popuga') ]
1096
@pirate.parrots.each { |parrot| parrot.name = '' }
1097
assert !@pirate.valid?
1100
test "should not automatically validate associations without :validate => true" do
1101
assert @pirate.valid?
1102
@pirate.non_validated_parrots = [ Parrot.new(:name => 'popuga') ]
1103
@pirate.non_validated_parrots.each { |parrot| parrot.name = '' }
1104
assert @pirate.valid?
1108
class TestAutosaveAssociationValidationMethodsGeneration < ActiveRecord::TestCase
1109
self.use_transactional_fixtures = false
1112
@pirate = Pirate.new
1115
test "should generate validation methods for has_many associations" do
1116
assert @pirate.respond_to?(:validate_associated_records_for_birds)
1119
test "should generate validation methods for has_one associations with :validate => true" do
1120
assert @pirate.respond_to?(:validate_associated_records_for_ship)
1123
test "should not generate validation methods for has_one associations without :validate => true" do
1124
assert !@pirate.respond_to?(:validate_associated_records_for_non_validated_ship)
1127
test "should generate validation methods for belongs_to associations with :validate => true" do
1128
assert @pirate.respond_to?(:validate_associated_records_for_parrot)
1131
test "should not generate validation methods for belongs_to associations without :validate => true" do
1132
assert !@pirate.respond_to?(:validate_associated_records_for_non_validated_parrot)
1135
test "should generate validation methods for HABTM associations with :validate => true" do
1136
assert @pirate.respond_to?(:validate_associated_records_for_parrots)
1139
test "should not generate validation methods for HABTM associations without :validate => true" do
1140
assert !@pirate.respond_to?(:validate_associated_records_for_non_validated_parrots)