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_save_fails_for_invalid_has_one
42 firm
= Firm
.find(:first)
45 firm
.account
= Account
.new
47 assert
!firm
.account
.valid
?
50 assert_equal
"is invalid", firm
.errors
.on("account")
53 def test_save_succeeds_for_invalid_has_one_with_validate_false
54 firm
= Firm
.find(:first)
57 firm
.unvalidated_account
= Account
.new
59 assert
!firm
.unvalidated_account
.valid
?
64 def test_build_before_child_saved
67 account
= firm
.account
.build("credit_limit" => 1000)
68 assert_equal account
, firm
.account
69 assert account
.new_record
?
71 assert_equal account
, firm
.account
72 assert
!account
.new_record
?
75 def test_build_before_either_saved
76 firm
= Firm
.new("name" => "GlobalMegaCorp")
78 firm
.account
= account
= Account
.new("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_assignment_before_parent_saved
87 firm
= Firm
.new("name" => "GlobalMegaCorp")
88 firm
.account
= a
= Account
.find(1)
89 assert firm
.new_record
?
90 assert_equal a
, firm
.account
92 assert_equal a
, firm
.account
93 assert_equal a
, firm
.account(true)
96 def test_assignment_before_either_saved
97 firm
= Firm
.new("name" => "GlobalMegaCorp")
98 firm
.account
= a
= Account
.new("credit_limit" => 1000)
99 assert firm
.new_record
?
101 assert_equal a
, firm
.account
103 assert
!firm
.new_record
?
104 assert
!a
.new_record
?
105 assert_equal a
, firm
.account
106 assert_equal a
, firm
.account(true)
109 def test_not_resaved_when_unchanged
110 firm
= Firm
.find(:first, :include => :account)
111 firm
.name
+= '-changed'
112 assert_queries(1) { firm
.save
! }
114 firm
= Firm
.find(:first)
115 firm
.account
= Account
.find(:first)
116 assert_queries(Firm
.partial_updates
? ? 0 : 1) { firm
.save
! }
118 firm
= Firm
.find(:first).clone
119 firm
.account
= Account
.find(:first)
120 assert_queries(2) { firm
.save
! }
122 firm
= Firm
.find(:first).clone
123 firm
.account
= Account
.find(:first).clone
124 assert_queries(2) { firm
.save
! }
128 class TestDefaultAutosaveAssociationOnABelongsToAssociation
< ActiveRecord
::TestCase
129 def test_save_fails_for_invalid_belongs_to
130 assert log
= AuditLog
.create(:developer_id => 0, :message => "")
132 log
.developer
= Developer
.new
133 assert
!log
.developer
.valid
?
136 assert_equal
"is invalid", log
.errors
.on("developer")
139 def test_save_succeeds_for_invalid_belongs_to_with_validate_false
140 assert log
= AuditLog
.create(:developer_id => 0, :message=> "")
142 log
.unvalidated_developer
= Developer
.new
143 assert
!log
.unvalidated_developer
.valid
?
148 def test_assignment_before_parent_saved
149 client
= Client
.find(:first)
150 apple
= Firm
.new("name" => "Apple")
152 assert_equal apple
, client
.firm
153 assert apple
.new_record
?
156 assert
!apple
.new_record
?
157 assert_equal apple
, client
.firm
158 assert_equal apple
, client
.firm(true)
161 def test_assignment_before_either_saved
162 final_cut
= Client
.new("name" => "Final Cut")
163 apple
= Firm
.new("name" => "Apple")
164 final_cut
.firm
= apple
165 assert final_cut
.new_record
?
166 assert apple
.new_record
?
167 assert final_cut
.save
168 assert
!final_cut
.new_record
?
169 assert
!apple
.new_record
?
170 assert_equal apple
, final_cut
.firm
171 assert_equal apple
, final_cut
.firm(true)
174 def test_store_two_association_with_one_save
175 num_orders
= Order
.count
176 num_customers
= Customer
.count
179 customer1
= order
.billing
= Customer
.new
180 customer2
= order
.shipping
= Customer
.new
182 assert_equal customer1
, order
.billing
183 assert_equal customer2
, order
.shipping
187 assert_equal customer1
, order
.billing
188 assert_equal customer2
, order
.shipping
190 assert_equal num_orders
+1, Order
.count
191 assert_equal num_customers
+2, Customer
.count
194 def test_store_association_in_two_relations_with_one_save
195 num_orders
= Order
.count
196 num_customers
= Customer
.count
199 customer
= order
.billing
= order
.shipping
= Customer
.new
201 assert_equal customer
, order
.billing
202 assert_equal customer
, order
.shipping
206 assert_equal customer
, order
.billing
207 assert_equal customer
, order
.shipping
209 assert_equal num_orders
+1, Order
.count
210 assert_equal num_customers
+1, Customer
.count
213 def test_store_association_in_two_relations_with_one_save_in_existing_object
214 num_orders
= Order
.count
215 num_customers
= Customer
.count
218 customer
= order
.billing
= order
.shipping
= Customer
.new
220 assert_equal customer
, order
.billing
221 assert_equal customer
, order
.shipping
225 assert_equal customer
, order
.billing
226 assert_equal customer
, order
.shipping
228 assert_equal num_orders
+1, Order
.count
229 assert_equal num_customers
+1, Customer
.count
232 def test_store_association_in_two_relations_with_one_save_in_existing_object_with_values
233 num_orders
= Order
.count
234 num_customers
= Customer
.count
237 customer
= order
.billing
= order
.shipping
= Customer
.new
239 assert_equal customer
, order
.billing
240 assert_equal customer
, order
.shipping
244 customer
= order
.billing
= order
.shipping
= Customer
.new
249 assert_equal customer
, order
.billing
250 assert_equal customer
, order
.shipping
252 assert_equal num_orders
+1, Order
.count
253 assert_equal num_customers
+2, Customer
.count
257 class TestDefaultAutosaveAssociationOnAHasManyAssociation
< ActiveRecord
::TestCase
258 fixtures
:companies, :people
260 def test_invalid_adding
262 assert
!(firm
.clients_of_firm
<< c
= Client
.new
)
269 def test_invalid_adding_before_save
270 no_of_firms
= Firm
.count
271 no_of_clients
= Client
.count
272 new_firm
= Firm
.new("name" => "A New Firm, Inc")
273 new_firm
.clients_of_firm
.concat([c
= Client
.new
, Client
.new("name" => "Apple")])
276 assert
!new_firm
.valid
?
277 assert
!new_firm
.save
279 assert new_firm
.new_record
?
282 def test_invalid_adding_with_validate_false
283 firm
= Firm
.find(:first)
285 firm
.unvalidated_clients_of_firm
<< client
288 assert
!client
.valid
?
290 assert client
.new_record
?
293 def test_valid_adding_with_validate_false
294 no_of_clients
= Client
.count
296 firm
= Firm
.find(:first)
297 client
= Client
.new("name" => "Apple")
301 assert client
.new_record
?
303 firm
.unvalidated_clients_of_firm
<< client
306 assert
!client
.new_record
?
307 assert_equal no_of_clients
+1, Client
.count
310 def test_invalid_build
311 new_client
= companies(:first_firm).clients_of_firm
.build
312 assert new_client
.new_record
?
313 assert
!new_client
.valid
?
314 assert_equal new_client
, companies(:first_firm).clients_of_firm
.last
315 assert
!companies(:first_firm).save
316 assert new_client
.new_record
?
317 assert_equal
1, companies(:first_firm).clients_of_firm(true).size
320 def test_adding_before_save
321 no_of_firms
= Firm
.count
322 no_of_clients
= Client
.count
324 new_firm
= Firm
.new("name" => "A New Firm, Inc")
325 c
= Client
.new("name" => "Apple")
327 new_firm
.clients_of_firm
.push Client
.new("name" => "Natural Company")
328 assert_equal
1, new_firm
.clients_of_firm
.size
329 new_firm
.clients_of_firm
<< c
330 assert_equal
2, new_firm
.clients_of_firm
.size
332 assert_equal no_of_firms
, Firm
.count
# Firm was not saved to database.
333 assert_equal no_of_clients
, Client
.count
# Clients were not saved to database.
335 assert
!new_firm
.new_record
?
336 assert
!c
.new_record
?
337 assert_equal new_firm
, c
.firm
338 assert_equal no_of_firms
+1, Firm
.count
# Firm was saved to database.
339 assert_equal no_of_clients
+2, Client
.count
# Clients were saved to database.
341 assert_equal
2, new_firm
.clients_of_firm
.size
342 assert_equal
2, new_firm
.clients_of_firm(true).size
346 firm
= Firm
.new("name" => "Apple")
347 firm
.client_ids
= [companies(:first_client).id
, companies(:second_client).id
]
350 assert_equal
2, firm
.clients
.length
351 assert firm
.clients
.include?(companies(:second_client))
354 def test_assign_ids_for_through_a_belongs_to
355 post
= Post
.new(:title => "Assigning IDs works!", :body => "You heared it here first, folks!")
356 post
.person_ids
= [people(:david).id
, people(:michael).id
]
359 assert_equal
2, post
.people
.length
360 assert post
.people
.include?(people(:david))
363 def test_build_before_save
364 company
= companies(:first_firm)
365 new_client
= assert_no_queries
{ company
.clients_of_firm
.build("name" => "Another Client") }
366 assert
!company
.clients_of_firm
.loaded
?
368 company
.name
+= '-changed'
369 assert_queries(2) { assert company
.save
}
370 assert
!new_client
.new_record
?
371 assert_equal
2, company
.clients_of_firm(true).size
374 def test_build_many_before_save
375 company
= companies(:first_firm)
376 new_clients
= assert_no_queries
{ company
.clients_of_firm
.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) }
378 company
.name
+= '-changed'
379 assert_queries(3) { assert company
.save
}
380 assert_equal
3, company
.clients_of_firm(true).size
383 def test_build_via_block_before_save
384 company
= companies(:first_firm)
385 new_client
= assert_no_queries
{ company
.clients_of_firm
.build
{|client
| client
.name
= "Another Client" } }
386 assert
!company
.clients_of_firm
.loaded
?
388 company
.name
+= '-changed'
389 assert_queries(2) { assert company
.save
}
390 assert
!new_client
.new_record
?
391 assert_equal
2, company
.clients_of_firm(true).size
394 def test_build_many_via_block_before_save
395 company
= companies(:first_firm)
396 new_clients
= assert_no_queries
do
397 company
.clients_of_firm
.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) do |client
|
398 client
.name
= "changed"
402 company
.name
+= '-changed'
403 assert_queries(3) { assert company
.save
}
404 assert_equal
3, company
.clients_of_firm(true).size
407 def test_replace_on_new_object
408 firm
= Firm
.new("name" => "New Firm")
409 firm
.clients
= [companies(:second_client), Client
.new("name" => "New Client")]
412 assert_equal
2, firm
.clients
.length
413 assert firm
.clients
.include?(Client
.find_by_name("New Client"))
417 class TestDestroyAsPartOfAutosaveAssociation
< ActiveRecord
::TestCase
418 self.use_transactional_fixtures
= false
421 @pirate = Pirate
.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
422 @ship = @pirate.create_ship(:name => 'Nights Dirty Lightning')
426 def test_a_marked_for_destruction_record_should_not_be_be_marked_after_reload
427 @pirate.mark_for_destruction
428 @pirate.ship
.mark_for_destruction
430 assert
!@pirate.reload
.marked_for_destruction
?
431 assert
!@pirate.ship
.marked_for_destruction
?
435 def test_should_destroy_a_child_association_as_part_of_the_save_transaction_if_it_was_marked_for_destroyal
436 assert
!@pirate.ship
.marked_for_destruction
?
438 @pirate.ship
.mark_for_destruction
441 assert
@pirate.ship
.marked_for_destruction
?
442 assert Ship
.find_by_id(id
)
445 assert_nil
@pirate.reload
.ship
446 assert_nil Ship
.find_by_id(id
)
449 def test_should_skip_validation_on_a_child_association_if_marked_for_destruction
450 @pirate.ship
.name
= ''
451 assert
!@pirate.valid
?
453 @pirate.ship
.mark_for_destruction
454 assert_difference('Ship.count', -1) { @pirate.save
! }
457 def test_should_rollback_destructions_if_an_exception_occurred_while_saving_a_child
458 # Stub the save method of the @pirate.ship instance to destroy and then raise an exception
459 class << @pirate.ship
467 assert_raise(RuntimeError
) { assert
!@pirate.save
}
468 assert_not_nil
@pirate.reload
.ship
472 def test_should_destroy_a_parent_association_as_part_of_the_save_transaction_if_it_was_marked_for_destroyal
473 assert
!@ship.pirate
.marked_for_destruction
?
475 @ship.pirate
.mark_for_destruction
478 assert
@ship.pirate
.marked_for_destruction
?
479 assert Pirate
.find_by_id(id
)
482 assert_nil
@ship.reload
.pirate
483 assert_nil Pirate
.find_by_id(id
)
486 def test_should_skip_validation_on_a_parent_association_if_marked_for_destruction
487 @ship.pirate
.catchphrase
= ''
490 @ship.pirate
.mark_for_destruction
491 assert_difference('Pirate.count', -1) { @ship.save
! }
494 def test_should_rollback_destructions_if_an_exception_occurred_while_saving_a_parent
495 # Stub the save method of the @ship.pirate instance to destroy and then raise an exception
496 class << @ship.pirate
504 assert_raise(RuntimeError
) { assert
!@ship.save
}
505 assert_not_nil
@ship.reload
.pirate
508 # has_many & has_and_belongs_to
509 %w
{ parrots birds
}.each
do |association_name
|
510 define_method("test_should_destroy_#{association_name}_as_part_of_the_save_transaction_if_they_were_marked_for_destroyal") do
511 2.times
{ |i
| @pirate.send(association_name
).create
!(:name => "#{association_name}_#{i}") }
513 assert
!@pirate.send(association_name
).any
? { |child
| child
.marked_for_destruction
? }
515 @pirate.send(association_name
).each
{ |child
| child
.mark_for_destruction
}
516 klass
= @pirate.send(association_name
).first
.class
517 ids
= @pirate.send(association_name
).map(&:id)
519 assert
@pirate.send(association_name
).all
? { |child
| child
.marked_for_destruction
? }
520 ids
.each
{ |id
| assert klass
.find_by_id(id
) }
523 assert
@pirate.reload
.send(association_name
).empty
?
524 ids
.each
{ |id
| assert_nil klass
.find_by_id(id
) }
527 define_method("test_should_skip_validation_on_the_#{association_name}_association_if_marked_for_destruction") do
528 2.times
{ |i
| @pirate.send(association_name
).create
!(:name => "#{association_name}_#{i}") }
529 children
= @pirate.send(association_name
)
531 children
.each
{ |child
| child
.name
= '' }
532 assert
!@pirate.valid
?
534 children
.each
{ |child
| child
.mark_for_destruction
}
535 assert_difference("#{association_name.classify}.count", -2) { @pirate.save
! }
538 define_method("test_should_rollback_destructions_if_an_exception_occurred_while_saving_#{association_name}") do
539 2.times
{ |i
| @pirate.send(association_name
).create
!(:name => "#{association_name}_#{i}") }
540 before
= @pirate.send(association_name
).map
{ |c
| c
}
542 # Stub the save method of the first child to destroy and the second to raise an exception
543 class << before
.first
556 assert_raise(RuntimeError
) { assert
!@pirate.save
}
557 assert_equal before
, @pirate.reload
.send(association_name
)
560 # Add and remove callbacks tests for association collections.
561 %w
{ method proc
}.each
do |callback_type
|
562 define_method("test_should_run_add_callback_#{callback_type}s_for_#{association_name}") do
563 association_name_with_callbacks
= "#{association_name}_with_#{callback_type}_callbacks"
565 pirate
= Pirate
.new(:catchphrase => "Arr")
566 pirate
.send(association_name_with_callbacks
).build(:name => "Crowe the One-Eyed")
569 "before_adding_#{callback_type}_#{association_name.singularize}_<new>",
570 "after_adding_#{callback_type}_#{association_name.singularize}_<new>"
573 assert_equal expected
, pirate
.ship_log
576 define_method("test_should_run_remove_callback_#{callback_type}s_for_#{association_name}") do
577 association_name_with_callbacks
= "#{association_name}_with_#{callback_type}_callbacks"
579 @pirate.send(association_name_with_callbacks
).create
!(:name => "Crowe the One-Eyed")
580 @pirate.send(association_name_with_callbacks
).each
{ |c
| c
.mark_for_destruction
}
581 child_id
= @pirate.send(association_name_with_callbacks
).first
.id
583 @pirate.ship_log
.clear
587 "before_removing_#{callback_type}_#{association_name.singularize}_#{child_id}",
588 "after_removing_#{callback_type}_#{association_name.singularize}_#{child_id}"
591 assert_equal expected
, @pirate.ship_log
597 class TestAutosaveAssociationOnAHasOneAssociation
< ActiveRecord
::TestCase
598 self.use_transactional_fixtures
= false
601 @pirate = Pirate
.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
602 @ship = @pirate.create_ship(:name => 'Nights Dirty Lightning')
605 def test_should_still_work_without_an_associated_model
607 @pirate.reload
.catchphrase
= "Arr"
609 assert
'Arr', @pirate.reload
.catchphrase
612 def test_should_automatically_save_the_associated_model
613 @pirate.ship
.name
= 'The Vile Insanity'
615 assert_equal
'The Vile Insanity', @pirate.reload
.ship
.name
618 def test_should_automatically_save_bang_the_associated_model
619 @pirate.ship
.name
= 'The Vile Insanity'
621 assert_equal
'The Vile Insanity', @pirate.reload
.ship
.name
624 def test_should_automatically_validate_the_associated_model
625 @pirate.ship
.name
= ''
626 assert
!@pirate.valid
?
627 assert
!@pirate.errors
.on(:ship_name).blank
?
630 def test_should_merge_errors_on_the_associated_models_onto_the_parent_even_if_it_is_not_valid
631 @pirate.ship
.name
= nil
632 @pirate.catchphrase
= nil
633 assert
!@pirate.valid
?
634 assert
!@pirate.errors
.on(:ship_name).blank
?
635 assert
!@pirate.errors
.on(:catchphrase).blank
?
638 def test_should_still_allow_to_bypass_validations_on_the_associated_model
639 @pirate.catchphrase
= ''
640 @pirate.ship
.name
= ''
642 assert_equal
['', ''], [@pirate.reload
.catchphrase
, @pirate.ship
.name
]
645 def test_should_allow_to_bypass_validations_on_associated_models_at_any_depth
646 2.times
{ |i
| @pirate.ship
.parts
.create
!(:name => "part #{i}") }
648 @pirate.catchphrase
= ''
649 @pirate.ship
.name
= ''
650 @pirate.ship
.parts
.each
{ |part
| part
.name
= '' }
653 values
= [@pirate.reload
.catchphrase
, @pirate.ship
.name
, *@pirate.ship
.parts
.map(&:name)]
654 assert_equal
['', '', '', ''], values
657 def test_should_still_raise_an_ActiveRecordRecord_Invalid_exception_if_we_want_that
658 @pirate.ship
.name
= ''
659 assert_raise(ActiveRecord
::RecordInvalid) do
664 def test_should_rollback_any_changes_if_an_exception_occurred_while_saving
665 before
= [@pirate.catchphrase
, @pirate.ship
.name
]
667 @pirate.catchphrase
= 'Arr'
668 @pirate.ship
.name
= 'The Vile Insanity'
670 # Stub the save method of the @pirate.ship instance to raise an exception
671 class << @pirate.ship
678 assert_raise(RuntimeError
) { assert
!@pirate.save
}
679 assert_equal before
, [@pirate.reload
.catchphrase
, @pirate.ship
.name
]
682 def test_should_not_load_the_associated_model
683 assert_queries(1) { @pirate.catchphrase
= 'Arr'; @pirate.save
! }
687 class TestAutosaveAssociationOnABelongsToAssociation
< ActiveRecord
::TestCase
688 self.use_transactional_fixtures
= false
691 @ship = Ship
.create(:name => 'Nights Dirty Lightning')
692 @pirate = @ship.create_pirate(:catchphrase => "Don' botharrr talkin' like one, savvy?")
695 def test_should_still_work_without_an_associated_model
697 @ship.reload
.name
= "The Vile Insanity"
699 assert
'The Vile Insanity', @ship.reload
.name
702 def test_should_automatically_save_the_associated_model
703 @ship.pirate
.catchphrase
= 'Arr'
705 assert_equal
'Arr', @ship.reload
.pirate
.catchphrase
708 def test_should_automatically_save_bang_the_associated_model
709 @ship.pirate
.catchphrase
= 'Arr'
711 assert_equal
'Arr', @ship.reload
.pirate
.catchphrase
714 def test_should_automatically_validate_the_associated_model
715 @ship.pirate
.catchphrase
= ''
717 assert
!@ship.errors
.on(:pirate_catchphrase).blank
?
720 def test_should_merge_errors_on_the_associated_model_onto_the_parent_even_if_it_is_not_valid
722 @ship.pirate
.catchphrase
= nil
724 assert
!@ship.errors
.on(:name).blank
?
725 assert
!@ship.errors
.on(:pirate_catchphrase).blank
?
728 def test_should_still_allow_to_bypass_validations_on_the_associated_model
729 @ship.pirate
.catchphrase
= ''
732 assert_equal
['', ''], [@ship.reload
.name
, @ship.pirate
.catchphrase
]
735 def test_should_still_raise_an_ActiveRecordRecord_Invalid_exception_if_we_want_that
736 @ship.pirate
.catchphrase
= ''
737 assert_raise(ActiveRecord
::RecordInvalid) do
742 def test_should_rollback_any_changes_if_an_exception_occurred_while_saving
743 before
= [@ship.pirate
.catchphrase
, @ship.name
]
745 @ship.pirate
.catchphrase
= 'Arr'
746 @ship.name
= 'The Vile Insanity'
748 # Stub the save method of the @ship.pirate instance to raise an exception
749 class << @ship.pirate
756 assert_raise(RuntimeError
) { assert
!@ship.save
}
757 # TODO: Why does using reload on @ship looses the associated pirate?
758 assert_equal before
, [@ship.pirate
.reload
.catchphrase
, @ship.reload
.name
]
761 def test_should_not_load_the_associated_model
762 assert_queries(1) { @ship.name
= 'The Vile Insanity'; @ship.save
! }
766 module AutosaveAssociationOnACollectionAssociationTests
767 def test_should_automatically_save_the_associated_models
768 new_names
= ['Grace OMalley', 'Privateers Greed']
769 @pirate.send(@association_name).each_with_index
{ |child
, i
| child
.name
= new_names
[i
] }
772 assert_equal new_names
, @pirate.reload
.send(@association_name).map(&:name)
775 def test_should_automatically_save_bang_the_associated_models
776 new_names
= ['Grace OMalley', 'Privateers Greed']
777 @pirate.send(@association_name).each_with_index
{ |child
, i
| child
.name
= new_names
[i
] }
780 assert_equal new_names
, @pirate.reload
.send(@association_name).map(&:name)
783 def test_should_automatically_validate_the_associated_models
784 @pirate.send(@association_name).each
{ |child
| child
.name
= '' }
786 assert
!@pirate.valid
?
787 assert_equal
"can't be blank", @pirate.errors
.on("#{@association_name}_name")
788 assert
@pirate.errors
.on(@association_name).blank
?
791 def test_should_not_use_default_invalid_error_on_associated_models
792 @pirate.send(@association_name).build(:name => '')
794 assert
!@pirate.valid
?
795 assert_equal
"can't be blank", @pirate.errors
.on("#{@association_name}_name")
796 assert
@pirate.errors
.on(@association_name).blank
?
799 def test_should_merge_errors_on_the_associated_models_onto_the_parent_even_if_it_is_not_valid
800 @pirate.send(@association_name).each
{ |child
| child
.name
= '' }
801 @pirate.catchphrase
= nil
803 assert
!@pirate.valid
?
804 assert_equal
"can't be blank", @pirate.errors
.on("#{@association_name}_name")
805 assert
!@pirate.errors
.on(:catchphrase).blank
?
808 def test_should_allow_to_bypass_validations_on_the_associated_models_on_update
809 @pirate.catchphrase
= ''
810 @pirate.send(@association_name).each
{ |child
| child
.name
= '' }
812 assert
@pirate.save(false)
813 assert_equal
['', '', ''], [
814 @pirate.reload
.catchphrase
,
815 @pirate.send(@association_name).first
.name
,
816 @pirate.send(@association_name).last
.name
820 def test_should_validation_the_associated_models_on_create
821 assert_no_difference("#{ @association_name == :birds ? 'Bird' : 'Parrot' }.count") do
822 2.times
{ @pirate.send(@association_name).build
}
827 def test_should_allow_to_bypass_validations_on_the_associated_models_on_create
828 assert_difference("#{ @association_name == :birds ? 'Bird' : 'Parrot' }.count", +2) do
829 2.times
{ @pirate.send(@association_name).build
}
834 def test_should_rollback_any_changes_if_an_exception_occurred_while_saving
835 before
= [@pirate.catchphrase
, *@pirate.send(@association_name).map(&:name)]
836 new_names
= ['Grace OMalley', 'Privateers Greed']
838 @pirate.catchphrase
= 'Arr'
839 @pirate.send(@association_name).each_with_index
{ |child
, i
| child
.name
= new_names
[i
] }
841 # Stub the save method of the first child instance to raise an exception
842 class << @pirate.send(@association_name).first
849 assert_raise(RuntimeError
) { assert
!@pirate.save
}
850 assert_equal before
, [@pirate.reload
.catchphrase
, *@pirate.send(@association_name).map(&:name)]
853 def test_should_still_raise_an_ActiveRecordRecord_Invalid_exception_if_we_want_that
854 @pirate.send(@association_name).each
{ |child
| child
.name
= '' }
855 assert_raise(ActiveRecord
::RecordInvalid) do
860 def test_should_not_load_the_associated_models_if_they_were_not_loaded_yet
861 assert_queries(1) { @pirate.catchphrase
= 'Arr'; @pirate.save
! }
863 @pirate.send(@association_name).class # hack to load the target
866 @pirate.catchphrase
= 'Yarr'
867 new_names
= ['Grace OMalley', 'Privateers Greed']
868 @pirate.send(@association_name).each_with_index
{ |child
, i
| child
.name
= new_names
[i
] }
874 class TestAutosaveAssociationOnAHasManyAssociation
< ActiveRecord
::TestCase
875 self.use_transactional_fixtures
= false
878 @association_name = :birds
880 @pirate = Pirate
.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
881 @child_1 = @pirate.birds
.create(:name => 'Posideons Killer')
882 @child_2 = @pirate.birds
.create(:name => 'Killer bandita Dionne')
885 include AutosaveAssociationOnACollectionAssociationTests
888 class TestAutosaveAssociationOnAHasAndBelongsToManyAssociation
< ActiveRecord
::TestCase
889 self.use_transactional_fixtures
= false
892 @association_name = :parrots
895 @pirate = Pirate
.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
896 @child_1 = @pirate.parrots
.create(:name => 'Posideons Killer')
897 @child_2 = @pirate.parrots
.create(:name => 'Killer bandita Dionne')
900 include AutosaveAssociationOnACollectionAssociationTests