activerecord 2.3.4 → 2.3.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- data/CHANGELOG +8 -0
- data/Rakefile +1 -1
- data/lib/active_record/associations.rb +10 -7
- data/lib/active_record/associations/association_proxy.rb +7 -8
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +2 -2
- data/lib/active_record/associations/has_one_association.rb +9 -0
- data/lib/active_record/autosave_association.rb +32 -23
- data/lib/active_record/base.rb +7 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +6 -2
- data/lib/active_record/fixtures.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +0 -33
- data/lib/active_record/locking/pessimistic.rb +0 -22
- data/lib/active_record/nested_attributes.rb +101 -38
- data/lib/active_record/validations.rb +35 -35
- data/lib/active_record/version.rb +1 -1
- data/lib/activerecord.rb +1 -0
- data/test/cases/associations/has_many_associations_test.rb +12 -0
- data/test/cases/associations/has_many_through_associations_test.rb +22 -0
- data/test/cases/associations/has_one_associations_test.rb +21 -0
- data/test/cases/autosave_association_test.rb +230 -11
- data/test/cases/base_test.rb +2 -0
- data/test/cases/connection_test_mysql.rb +8 -0
- data/test/cases/fixtures_test.rb +2 -2
- data/test/cases/locking_test.rb +0 -18
- data/test/cases/nested_attributes_test.rb +109 -37
- data/test/cases/reflection_test.rb +3 -3
- data/test/cases/validations_i18n_test.rb +8 -0
- data/test/cases/validations_test.rb +37 -9
- data/test/fixtures/accounts.yml +1 -0
- data/test/fixtures/fixture_database.sqlite3 +0 -0
- data/test/fixtures/fixture_database_2.sqlite3 +0 -0
- data/test/models/company.rb +10 -0
- data/test/models/pirate.rb +9 -2
- data/test/models/treasure.rb +2 -0
- data/test/schema/mysql_specific_schema.rb +12 -0
- data/test/schema/schema.rb +1 -0
- metadata +4 -4
@@ -27,11 +27,13 @@ module ActiveRecord
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def message
|
30
|
-
|
30
|
+
# When type is a string, it means that we do not have to do a lookup, because
|
31
|
+
# the user already sent the "final" message.
|
32
|
+
type.is_a?(String) ? type : generate_message(default_options)
|
31
33
|
end
|
32
34
|
|
33
35
|
def full_message
|
34
|
-
attribute.to_s == 'base' ? message : generate_full_message(
|
36
|
+
attribute.to_s == 'base' ? message : generate_full_message(default_options)
|
35
37
|
end
|
36
38
|
|
37
39
|
alias :to_s :message
|
@@ -60,24 +62,19 @@ module ActiveRecord
|
|
60
62
|
# <li><tt>activerecord.errors.messages.blank</tt></li>
|
61
63
|
# <li>any default you provided through the +options+ hash (in the activerecord.errors scope)</li>
|
62
64
|
# </ol>
|
63
|
-
def generate_message(
|
65
|
+
def generate_message(options = {})
|
64
66
|
keys = @base.class.self_and_descendants_from_active_record.map do |klass|
|
65
|
-
[ :"models.#{klass.name.underscore}.attributes.#{attribute}.#{message}",
|
66
|
-
:"models.#{klass.name.underscore}.#{message}" ]
|
67
|
+
[ :"models.#{klass.name.underscore}.attributes.#{attribute}.#{@message}",
|
68
|
+
:"models.#{klass.name.underscore}.#{@message}" ]
|
67
69
|
end.flatten
|
68
70
|
|
69
71
|
keys << options.delete(:default)
|
70
|
-
keys << :"messages.#{message}"
|
71
|
-
keys << message if message.is_a?(String)
|
72
|
-
keys << @type unless @type == message
|
72
|
+
keys << :"messages.#{@message}"
|
73
|
+
keys << @message if @message.is_a?(String)
|
74
|
+
keys << @type unless @type == @message
|
73
75
|
keys.compact!
|
74
76
|
|
75
|
-
options.
|
76
|
-
:scope => [:activerecord, :errors],
|
77
|
-
:model => @base.class.human_name,
|
78
|
-
:attribute => @base.class.human_attribute_name(attribute.to_s),
|
79
|
-
:value => value
|
80
|
-
|
77
|
+
options.merge!(:default => keys)
|
81
78
|
I18n.translate(keys.shift, options)
|
82
79
|
end
|
83
80
|
|
@@ -108,16 +105,24 @@ module ActiveRecord
|
|
108
105
|
# full_messages:
|
109
106
|
# title:
|
110
107
|
# blank: This title is screwed!
|
111
|
-
def generate_full_message(
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
108
|
+
def generate_full_message(options = {})
|
109
|
+
keys = [
|
110
|
+
:"full_messages.#{@message}",
|
111
|
+
:'full_messages.format',
|
112
|
+
'{{attribute}} {{message}}'
|
113
|
+
]
|
114
|
+
|
115
|
+
options.merge!(:default => keys, :message => self.message)
|
116
|
+
I18n.translate(keys.shift, options)
|
117
|
+
end
|
119
118
|
|
120
|
-
|
119
|
+
# Return user options with default options.
|
120
|
+
#
|
121
|
+
def default_options
|
122
|
+
options.reverse_merge :scope => [:activerecord, :errors],
|
123
|
+
:model => @base.class.human_name,
|
124
|
+
:attribute => @base.class.human_attribute_name(attribute.to_s),
|
125
|
+
:value => value
|
121
126
|
end
|
122
127
|
end
|
123
128
|
|
@@ -134,7 +139,8 @@ module ActiveRecord
|
|
134
139
|
end
|
135
140
|
|
136
141
|
def initialize(base) # :nodoc:
|
137
|
-
@base
|
142
|
+
@base = base
|
143
|
+
clear
|
138
144
|
end
|
139
145
|
|
140
146
|
# Adds an error to the base object instead of any particular attribute. This is used
|
@@ -150,16 +156,10 @@ module ActiveRecord
|
|
150
156
|
# error can be added to the same +attribute+ in which case an array will be returned on a call to <tt>on(attribute)</tt>.
|
151
157
|
# If no +messsage+ is supplied, :invalid is assumed.
|
152
158
|
# If +message+ is a Symbol, it will be translated, using the appropriate scope (see translate_error).
|
153
|
-
#
|
154
|
-
|
155
|
-
# message = generate_message(attribute, message, options)) if message.is_a?(Symbol)
|
156
|
-
# @errors[attribute.to_s] ||= []
|
157
|
-
# @errors[attribute.to_s] << message
|
158
|
-
# end
|
159
|
-
|
160
|
-
def add(error_or_attr, message = nil, options = {})
|
161
|
-
error, attribute = error_or_attr.is_a?(Error) ? [error_or_attr, error_or_attr.attribute] : [nil, error_or_attr]
|
159
|
+
#
|
160
|
+
def add(attribute, message = nil, options = {})
|
162
161
|
options[:message] = options.delete(:default) if options.has_key?(:default)
|
162
|
+
error, message = message, nil if message.is_a?(Error)
|
163
163
|
|
164
164
|
@errors[attribute.to_s] ||= []
|
165
165
|
@errors[attribute.to_s] << (error || Error.new(@base, attribute, message, options))
|
@@ -283,7 +283,7 @@ module ActiveRecord
|
|
283
283
|
|
284
284
|
# Removes all errors that have been added.
|
285
285
|
def clear
|
286
|
-
@errors =
|
286
|
+
@errors = ActiveSupport::OrderedHash.new
|
287
287
|
end
|
288
288
|
|
289
289
|
# Returns the total number of errors added. Two errors added to the same attribute will be counted as such.
|
@@ -321,7 +321,7 @@ module ActiveRecord
|
|
321
321
|
end
|
322
322
|
|
323
323
|
def generate_message(attribute, message = :invalid, options = {})
|
324
|
-
ActiveSupport::Deprecation.warn("ActiveRecord::Errors#generate_message has been deprecated. Please use ActiveRecord::Error
|
324
|
+
ActiveSupport::Deprecation.warn("ActiveRecord::Errors#generate_message has been deprecated. Please use ActiveRecord::Error.new().to_s.")
|
325
325
|
Error.new(@base, attribute, message, options).to_s
|
326
326
|
end
|
327
327
|
end
|
data/lib/activerecord.rb
CHANGED
@@ -651,6 +651,18 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
|
|
651
651
|
assert_equal 1, Client.find_all_by_client_of(firm.id).size
|
652
652
|
end
|
653
653
|
|
654
|
+
def test_delete_all_association_with_primary_key_deletes_correct_records
|
655
|
+
firm = Firm.find(:first)
|
656
|
+
# break the vanilla firm_id foreign key
|
657
|
+
assert_equal 2, firm.clients.count
|
658
|
+
firm.clients.first.update_attribute(:firm_id, nil)
|
659
|
+
assert_equal 1, firm.clients(true).count
|
660
|
+
assert_equal 1, firm.clients_using_primary_key_with_delete_all.count
|
661
|
+
old_record = firm.clients_using_primary_key_with_delete_all.first
|
662
|
+
firm = Firm.find(:first)
|
663
|
+
firm.destroy
|
664
|
+
assert Client.find_by_id(old_record.id).nil?
|
665
|
+
end
|
654
666
|
|
655
667
|
def test_creation_respects_hash_condition
|
656
668
|
ms_client = companies(:first_firm).clients_like_ms_with_hash_conditions.build
|
@@ -132,6 +132,28 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
|
|
132
132
|
assert !posts(:welcome).reload.people(true).include?(people(:michael))
|
133
133
|
end
|
134
134
|
|
135
|
+
def test_replace_order_is_preserved
|
136
|
+
posts(:welcome).people.clear
|
137
|
+
posts(:welcome).people = [people(:david), people(:michael)]
|
138
|
+
assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.all(:order => 'id').map(&:person_id)
|
139
|
+
|
140
|
+
# Test the inverse order in case the first success was a coincidence
|
141
|
+
posts(:welcome).people.clear
|
142
|
+
posts(:welcome).people = [people(:michael), people(:david)]
|
143
|
+
assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.all(:order => 'id').map(&:person_id)
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_replace_by_id_order_is_preserved
|
147
|
+
posts(:welcome).people.clear
|
148
|
+
posts(:welcome).person_ids = [people(:david).id, people(:michael).id]
|
149
|
+
assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.all(:order => 'id').map(&:person_id)
|
150
|
+
|
151
|
+
# Test the inverse order in case the first success was a coincidence
|
152
|
+
posts(:welcome).people.clear
|
153
|
+
posts(:welcome).person_ids = [people(:michael).id, people(:david).id]
|
154
|
+
assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.all(:order => 'id').map(&:person_id)
|
155
|
+
end
|
156
|
+
|
135
157
|
def test_associate_with_create
|
136
158
|
assert_queries(1) { posts(:thinking) }
|
137
159
|
|
@@ -36,6 +36,15 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
|
|
36
36
|
assert_equal accounts(:rails_core_account), firm.account_using_primary_key
|
37
37
|
end
|
38
38
|
|
39
|
+
def test_update_with_foreign_and_primary_keys
|
40
|
+
firm = companies(:first_firm)
|
41
|
+
account = firm.account_using_foreign_and_primary_keys
|
42
|
+
assert_equal Account.find_by_firm_name(firm.name), account
|
43
|
+
firm.save
|
44
|
+
firm.reload
|
45
|
+
assert_equal account, firm.account_using_foreign_and_primary_keys
|
46
|
+
end
|
47
|
+
|
39
48
|
def test_can_marshal_has_one_association_with_nil_target
|
40
49
|
firm = Firm.new
|
41
50
|
assert_nothing_raised do
|
@@ -306,4 +315,16 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
|
|
306
315
|
Firm.find(@firm.id, :include => :account).save!
|
307
316
|
end
|
308
317
|
end
|
318
|
+
|
319
|
+
def test_build_respects_hash_condition
|
320
|
+
account = companies(:first_firm).build_account_limit_500_with_hash_conditions
|
321
|
+
assert account.save
|
322
|
+
assert_equal 500, account.credit_limit
|
323
|
+
end
|
324
|
+
|
325
|
+
def test_create_respects_hash_condition
|
326
|
+
account = companies(:first_firm).create_account_limit_500_with_hash_conditions
|
327
|
+
assert !account.new_record?
|
328
|
+
assert_equal 500, account.credit_limit
|
329
|
+
end
|
309
330
|
end
|
@@ -436,6 +436,70 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa
|
|
436
436
|
end
|
437
437
|
end
|
438
438
|
|
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")
|
443
|
+
|
444
|
+
assert new_firm.new_record?
|
445
|
+
new_account.firm = new_firm
|
446
|
+
new_account.save!
|
447
|
+
|
448
|
+
assert !new_firm.new_record?
|
449
|
+
|
450
|
+
new_account = Account.new("credit_limit" => 1000)
|
451
|
+
new_autosaved_firm = Firm.new("name" => "some firm")
|
452
|
+
|
453
|
+
assert new_autosaved_firm.new_record?
|
454
|
+
new_account.unautosaved_firm = new_autosaved_firm
|
455
|
+
new_account.save!
|
456
|
+
|
457
|
+
assert new_autosaved_firm.new_record?
|
458
|
+
end
|
459
|
+
|
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)
|
463
|
+
|
464
|
+
assert account.new_record?
|
465
|
+
firm.account = account
|
466
|
+
firm.save!
|
467
|
+
|
468
|
+
assert !account.new_record?
|
469
|
+
|
470
|
+
firm = Firm.new("name" => "some firm")
|
471
|
+
account = Account.new("credit_limit" => 1000)
|
472
|
+
|
473
|
+
firm.unautosaved_account = account
|
474
|
+
|
475
|
+
assert account.new_record?
|
476
|
+
firm.unautosaved_account = account
|
477
|
+
firm.save!
|
478
|
+
|
479
|
+
assert account.new_record?
|
480
|
+
end
|
481
|
+
|
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)
|
485
|
+
|
486
|
+
assert account.new_record?
|
487
|
+
firm.accounts << account
|
488
|
+
|
489
|
+
firm.save!
|
490
|
+
assert !account.new_record?
|
491
|
+
|
492
|
+
firm = Firm.new("name" => "some firm")
|
493
|
+
account = Account.new("credit_limit" => 1000)
|
494
|
+
|
495
|
+
assert account.new_record?
|
496
|
+
firm.unautosaved_accounts << account
|
497
|
+
|
498
|
+
firm.save!
|
499
|
+
assert account.new_record?
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
439
503
|
class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
|
440
504
|
self.use_transactional_fixtures = false
|
441
505
|
|
@@ -473,9 +537,17 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
|
|
473
537
|
assert !@pirate.valid?
|
474
538
|
|
475
539
|
@pirate.ship.mark_for_destruction
|
540
|
+
@pirate.ship.expects(:valid?).never
|
476
541
|
assert_difference('Ship.count', -1) { @pirate.save! }
|
477
542
|
end
|
478
543
|
|
544
|
+
def test_a_child_marked_for_destruction_should_not_be_destroyed_twice
|
545
|
+
@pirate.ship.mark_for_destruction
|
546
|
+
assert @pirate.save
|
547
|
+
@pirate.ship.expects(:destroy).never
|
548
|
+
assert @pirate.save
|
549
|
+
end
|
550
|
+
|
479
551
|
def test_should_rollback_destructions_if_an_exception_occurred_while_saving_a_child
|
480
552
|
# Stub the save method of the @pirate.ship instance to destroy and then raise an exception
|
481
553
|
class << @pirate.ship
|
@@ -510,9 +582,17 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
|
|
510
582
|
assert !@ship.valid?
|
511
583
|
|
512
584
|
@ship.pirate.mark_for_destruction
|
585
|
+
@ship.pirate.expects(:valid?).never
|
513
586
|
assert_difference('Pirate.count', -1) { @ship.save! }
|
514
587
|
end
|
515
588
|
|
589
|
+
def test_a_parent_marked_for_destruction_should_not_be_destroyed_twice
|
590
|
+
@ship.pirate.mark_for_destruction
|
591
|
+
assert @ship.save
|
592
|
+
@ship.pirate.expects(:destroy).never
|
593
|
+
assert @ship.save
|
594
|
+
end
|
595
|
+
|
516
596
|
def test_should_rollback_destructions_if_an_exception_occurred_while_saving_a_parent
|
517
597
|
# Stub the save method of the @ship.pirate instance to destroy and then raise an exception
|
518
598
|
class << @ship.pirate
|
@@ -553,9 +633,33 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
|
|
553
633
|
children.each { |child| child.name = '' }
|
554
634
|
assert !@pirate.valid?
|
555
635
|
|
556
|
-
children.each
|
636
|
+
children.each do |child|
|
637
|
+
child.mark_for_destruction
|
638
|
+
child.expects(:valid?).never
|
639
|
+
end
|
557
640
|
assert_difference("#{association_name.classify}.count", -2) { @pirate.save! }
|
558
641
|
end
|
642
|
+
|
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)
|
646
|
+
|
647
|
+
children.each { |child| child.name = '' }
|
648
|
+
assert !@pirate.valid?
|
649
|
+
|
650
|
+
children.each { |child| child.destroy }
|
651
|
+
assert @pirate.valid?
|
652
|
+
end
|
653
|
+
|
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)
|
657
|
+
|
658
|
+
children.each { |child| child.mark_for_destruction }
|
659
|
+
assert @pirate.save
|
660
|
+
children.each { |child| child.expects(:destroy).never }
|
661
|
+
assert @pirate.save
|
662
|
+
end
|
559
663
|
|
560
664
|
define_method("test_should_rollback_destructions_if_an_exception_occurred_while_saving_#{association_name}") do
|
561
665
|
2.times { |i| @pirate.send(association_name).create!(:name => "#{association_name}_#{i}") }
|
@@ -646,15 +750,15 @@ class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase
|
|
646
750
|
def test_should_automatically_validate_the_associated_model
|
647
751
|
@pirate.ship.name = ''
|
648
752
|
assert !@pirate.valid?
|
649
|
-
|
753
|
+
assert_equal "can't be blank", @pirate.errors.on(:"ship.name")
|
650
754
|
end
|
651
755
|
|
652
756
|
def test_should_merge_errors_on_the_associated_models_onto_the_parent_even_if_it_is_not_valid
|
653
757
|
@pirate.ship.name = nil
|
654
758
|
@pirate.catchphrase = nil
|
655
759
|
assert !@pirate.valid?
|
656
|
-
assert
|
657
|
-
assert
|
760
|
+
assert @pirate.errors.full_messages.include?("Name can't be blank")
|
761
|
+
assert @pirate.errors.full_messages.include?("Catchphrase can't be blank")
|
658
762
|
end
|
659
763
|
|
660
764
|
def test_should_still_allow_to_bypass_validations_on_the_associated_model
|
@@ -736,15 +840,15 @@ class TestAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase
|
|
736
840
|
def test_should_automatically_validate_the_associated_model
|
737
841
|
@ship.pirate.catchphrase = ''
|
738
842
|
assert !@ship.valid?
|
739
|
-
|
843
|
+
assert_equal "can't be blank", @ship.errors.on(:"pirate.catchphrase")
|
740
844
|
end
|
741
845
|
|
742
846
|
def test_should_merge_errors_on_the_associated_model_onto_the_parent_even_if_it_is_not_valid
|
743
847
|
@ship.name = nil
|
744
848
|
@ship.pirate.catchphrase = nil
|
745
849
|
assert !@ship.valid?
|
746
|
-
assert
|
747
|
-
assert
|
850
|
+
assert @ship.errors.full_messages.include?("Name can't be blank")
|
851
|
+
assert @ship.errors.full_messages.include?("Catchphrase can't be blank")
|
748
852
|
end
|
749
853
|
|
750
854
|
def test_should_still_allow_to_bypass_validations_on_the_associated_model
|
@@ -806,7 +910,7 @@ module AutosaveAssociationOnACollectionAssociationTests
|
|
806
910
|
@pirate.send(@association_name).each { |child| child.name = '' }
|
807
911
|
|
808
912
|
assert !@pirate.valid?
|
809
|
-
|
913
|
+
assert @pirate.errors.full_messages.include?("Name can't be blank")
|
810
914
|
assert @pirate.errors.on(@association_name).blank?
|
811
915
|
end
|
812
916
|
|
@@ -814,7 +918,7 @@ module AutosaveAssociationOnACollectionAssociationTests
|
|
814
918
|
@pirate.send(@association_name).build(:name => '')
|
815
919
|
|
816
920
|
assert !@pirate.valid?
|
817
|
-
assert_equal "can't be blank", @pirate.errors.on("#{@association_name}
|
921
|
+
assert_equal "can't be blank", @pirate.errors.on("#{@association_name}.name")
|
818
922
|
assert @pirate.errors.on(@association_name).blank?
|
819
923
|
end
|
820
924
|
|
@@ -823,7 +927,7 @@ module AutosaveAssociationOnACollectionAssociationTests
|
|
823
927
|
@pirate.catchphrase = nil
|
824
928
|
|
825
929
|
assert !@pirate.valid?
|
826
|
-
assert_equal "can't be blank", @pirate.errors.on("#{@association_name}
|
930
|
+
assert_equal "can't be blank", @pirate.errors.on("#{@association_name}.name")
|
827
931
|
assert !@pirate.errors.on(:catchphrase).blank?
|
828
932
|
end
|
829
933
|
|
@@ -920,4 +1024,119 @@ class TestAutosaveAssociationOnAHasAndBelongsToManyAssociation < ActiveRecord::T
|
|
920
1024
|
end
|
921
1025
|
|
922
1026
|
include AutosaveAssociationOnACollectionAssociationTests
|
923
|
-
end
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
class TestAutosaveAssociationValidationsOnAHasManyAssocication < ActiveRecord::TestCase
|
1030
|
+
self.use_transactional_fixtures = false
|
1031
|
+
|
1032
|
+
def setup
|
1033
|
+
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
1034
|
+
@pirate.birds.create(:name => 'cookoo')
|
1035
|
+
end
|
1036
|
+
|
1037
|
+
test "should automatically validate associations" do
|
1038
|
+
assert @pirate.valid?
|
1039
|
+
@pirate.birds.each { |bird| bird.name = '' }
|
1040
|
+
|
1041
|
+
assert !@pirate.valid?
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
class TestAutosaveAssociationValidationsOnAHasOneAssocication < ActiveRecord::TestCase
|
1046
|
+
self.use_transactional_fixtures = false
|
1047
|
+
|
1048
|
+
def setup
|
1049
|
+
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
1050
|
+
@pirate.create_ship(:name => 'titanic')
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
test "should automatically validate associations with :validate => true" do
|
1054
|
+
assert @pirate.valid?
|
1055
|
+
@pirate.ship.name = ''
|
1056
|
+
assert !@pirate.valid?
|
1057
|
+
end
|
1058
|
+
|
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?
|
1063
|
+
end
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
class TestAutosaveAssociationValidationsOnABelongsToAssocication < ActiveRecord::TestCase
|
1067
|
+
self.use_transactional_fixtures = false
|
1068
|
+
|
1069
|
+
def setup
|
1070
|
+
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
test "should automatically validate associations with :validate => true" do
|
1074
|
+
assert @pirate.valid?
|
1075
|
+
@pirate.parrot = Parrot.new(:name => '')
|
1076
|
+
assert !@pirate.valid?
|
1077
|
+
end
|
1078
|
+
|
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?
|
1083
|
+
end
|
1084
|
+
end
|
1085
|
+
|
1086
|
+
class TestAutosaveAssociationValidationsOnAHABTMAssocication < ActiveRecord::TestCase
|
1087
|
+
self.use_transactional_fixtures = false
|
1088
|
+
|
1089
|
+
def setup
|
1090
|
+
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
1091
|
+
end
|
1092
|
+
|
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?
|
1098
|
+
end
|
1099
|
+
|
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?
|
1105
|
+
end
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
class TestAutosaveAssociationValidationMethodsGeneration < ActiveRecord::TestCase
|
1109
|
+
self.use_transactional_fixtures = false
|
1110
|
+
|
1111
|
+
def setup
|
1112
|
+
@pirate = Pirate.new
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
test "should generate validation methods for has_many associations" do
|
1116
|
+
assert @pirate.respond_to?(:validate_associated_records_for_birds)
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
test "should generate validation methods for has_one associations with :validate => true" do
|
1120
|
+
assert @pirate.respond_to?(:validate_associated_records_for_ship)
|
1121
|
+
end
|
1122
|
+
|
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)
|
1125
|
+
end
|
1126
|
+
|
1127
|
+
test "should generate validation methods for belongs_to associations with :validate => true" do
|
1128
|
+
assert @pirate.respond_to?(:validate_associated_records_for_parrot)
|
1129
|
+
end
|
1130
|
+
|
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)
|
1133
|
+
end
|
1134
|
+
|
1135
|
+
test "should generate validation methods for HABTM associations with :validate => true" do
|
1136
|
+
assert @pirate.respond_to?(:validate_associated_records_for_parrots)
|
1137
|
+
end
|
1138
|
+
|
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)
|
1141
|
+
end
|
1142
|
+
end
|