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
data/test/cases/base_test.rb
CHANGED
@@ -474,6 +474,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
474
474
|
topic = Topic.find(1)
|
475
475
|
assert_equal topic, topic.delete, 'topic.delete did not return self'
|
476
476
|
assert topic.frozen?, 'topic not frozen after delete'
|
477
|
+
assert topic.destroyed?, 'topic not marked as being destroyed'
|
477
478
|
assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
|
478
479
|
end
|
479
480
|
|
@@ -486,6 +487,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
486
487
|
topic = Topic.find(1)
|
487
488
|
assert_equal topic, topic.destroy, 'topic.destroy did not return self'
|
488
489
|
assert topic.frozen?, 'topic not frozen after destroy'
|
490
|
+
assert topic.destroyed?, 'topic not marked as being destroyed'
|
489
491
|
assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
|
490
492
|
end
|
491
493
|
|
@@ -41,6 +41,14 @@ class MysqlConnectionTest < ActiveRecord::TestCase
|
|
41
41
|
sleep 2
|
42
42
|
@connection.verify!
|
43
43
|
assert @connection.active?
|
44
|
+
end
|
45
|
+
|
46
|
+
# Test that MySQL allows multiple results for stored procedures
|
47
|
+
if Mysql.const_defined?(:CLIENT_MULTI_RESULTS)
|
48
|
+
def test_multi_results
|
49
|
+
rows = ActiveRecord::Base.connection.select_rows('CALL ten();')
|
50
|
+
assert_equal 10, rows[0][0].to_i, "ten() did not return 10 as expected: #{rows.inspect}"
|
51
|
+
end
|
44
52
|
end
|
45
53
|
|
46
54
|
private
|
data/test/cases/fixtures_test.rb
CHANGED
@@ -519,8 +519,8 @@ class FoxyFixturesTest < ActiveRecord::TestCase
|
|
519
519
|
end
|
520
520
|
|
521
521
|
def test_identifies_consistently
|
522
|
-
assert_equal
|
523
|
-
assert_equal
|
522
|
+
assert_equal 207281424, Fixtures.identify(:ruby)
|
523
|
+
assert_equal 1066363776, Fixtures.identify(:sapphire_2)
|
524
524
|
end
|
525
525
|
|
526
526
|
TIMESTAMP_COLUMNS = %w(created_at created_on updated_at updated_on)
|
data/test/cases/locking_test.rb
CHANGED
@@ -38,24 +38,6 @@ class OptimisticLockingTest < ActiveRecord::TestCase
|
|
38
38
|
assert_raise(ActiveRecord::StaleObjectError) { p2.save! }
|
39
39
|
end
|
40
40
|
|
41
|
-
def test_lock_destroy
|
42
|
-
p1 = Person.find(1)
|
43
|
-
p2 = Person.find(1)
|
44
|
-
assert_equal 0, p1.lock_version
|
45
|
-
assert_equal 0, p2.lock_version
|
46
|
-
|
47
|
-
p1.first_name = 'stu'
|
48
|
-
p1.save!
|
49
|
-
assert_equal 1, p1.lock_version
|
50
|
-
assert_equal 0, p2.lock_version
|
51
|
-
|
52
|
-
assert_raises(ActiveRecord::StaleObjectError) { p2.destroy }
|
53
|
-
|
54
|
-
assert p1.destroy
|
55
|
-
assert_equal true, p1.frozen?
|
56
|
-
assert_raises(ActiveRecord::RecordNotFound) { Person.find(1) }
|
57
|
-
end
|
58
|
-
|
59
41
|
def test_lock_repeating
|
60
42
|
p1 = Person.find(1)
|
61
43
|
p2 = Person.find(1)
|
@@ -26,13 +26,13 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase
|
|
26
26
|
Pirate.accepts_nested_attributes_for :ship, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
30
|
-
assert_equal Hash.new, ActiveRecord::Base.
|
29
|
+
def test_base_should_have_an_empty_nested_attributes_options
|
30
|
+
assert_equal Hash.new, ActiveRecord::Base.nested_attributes_options
|
31
31
|
end
|
32
32
|
|
33
|
-
def
|
33
|
+
def test_should_add_a_proc_to_nested_attributes_options
|
34
34
|
[:parrots, :birds].each do |name|
|
35
|
-
assert_instance_of Proc, Pirate.
|
35
|
+
assert_instance_of Proc, Pirate.nested_attributes_options[name][:reject_if]
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
@@ -49,24 +49,66 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase
|
|
49
49
|
ship = pirate.create_ship(:name => 'Nights Dirty Lightning')
|
50
50
|
|
51
51
|
assert_no_difference('Ship.count') do
|
52
|
-
pirate.update_attributes(:ship_attributes => { '
|
52
|
+
pirate.update_attributes(:ship_attributes => { '_destroy' => true })
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
-
def
|
56
|
+
def test_a_model_should_respond_to_underscore_destroy_and_return_if_it_is_marked_for_destruction
|
57
57
|
ship = Ship.create!(:name => 'Nights Dirty Lightning')
|
58
|
-
assert !ship.
|
58
|
+
assert !ship._destroy
|
59
59
|
ship.mark_for_destruction
|
60
|
-
assert ship.
|
60
|
+
assert ship._destroy
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_underscore_delete_is_deprecated
|
64
|
+
ActiveSupport::Deprecation.expects(:warn)
|
65
|
+
ship = Ship.create!(:name => 'Nights Dirty Lightning')
|
66
|
+
ship._delete
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_reject_if_method_without_arguments
|
70
|
+
Pirate.accepts_nested_attributes_for :ship, :reject_if => :new_record?
|
71
|
+
|
72
|
+
pirate = Pirate.new(:catchphrase => "Stop wastin' me time")
|
73
|
+
pirate.ship_attributes = { :name => 'Black Pearl' }
|
74
|
+
assert_no_difference('Ship.count') { pirate.save! }
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_reject_if_method_with_arguments
|
78
|
+
Pirate.accepts_nested_attributes_for :ship, :reject_if => :reject_empty_ships_on_create
|
79
|
+
|
80
|
+
pirate = Pirate.new(:catchphrase => "Stop wastin' me time")
|
81
|
+
pirate.ship_attributes = { :name => 'Red Pearl', :_reject_me_if_new => true }
|
82
|
+
assert_no_difference('Ship.count') { pirate.save! }
|
83
|
+
|
84
|
+
# pirate.reject_empty_ships_on_create returns false for saved records
|
85
|
+
pirate.ship_attributes = { :name => 'Red Pearl', :_reject_me_if_new => true }
|
86
|
+
assert_difference('Ship.count') { pirate.save! }
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_reject_if_with_indifferent_keys
|
90
|
+
Pirate.accepts_nested_attributes_for :ship, :reject_if => proc {|attributes| attributes[:name].blank? }
|
91
|
+
|
92
|
+
pirate = Pirate.new(:catchphrase => "Stop wastin' me time")
|
93
|
+
pirate.ship_attributes = { :name => 'Hello Pearl' }
|
94
|
+
assert_difference('Ship.count') { pirate.save! }
|
61
95
|
end
|
62
96
|
end
|
63
97
|
|
64
98
|
class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
|
99
|
+
include AssertRaiseWithMessage
|
100
|
+
|
65
101
|
def setup
|
66
102
|
@pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
67
103
|
@ship = @pirate.create_ship(:name => 'Nights Dirty Lightning')
|
68
104
|
end
|
69
105
|
|
106
|
+
def test_should_raise_argument_error_if_trying_to_build_polymorphic_belongs_to
|
107
|
+
assert_raise_with_message ArgumentError, "Cannot build association looter. Are you trying to build a polymorphic one-to-one association?" do
|
108
|
+
Treasure.new(:name => 'pearl', :looter_attributes => {:catchphrase => "Arrr"})
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
70
112
|
def test_should_define_an_attribute_writer_method_for_the_association
|
71
113
|
assert_respond_to @pirate, :ship_attributes=
|
72
114
|
end
|
@@ -79,9 +121,9 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
|
|
79
121
|
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
|
80
122
|
end
|
81
123
|
|
82
|
-
def
|
124
|
+
def test_should_not_build_a_new_record_if_there_is_no_id_and_destroy_is_truthy
|
83
125
|
@ship.destroy
|
84
|
-
@pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger', :
|
126
|
+
@pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger', :_destroy => '1' }
|
85
127
|
|
86
128
|
assert_nil @pirate.ship
|
87
129
|
end
|
@@ -101,8 +143,8 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
|
|
101
143
|
assert_equal 'Nights Dirty Lightning', @ship.name
|
102
144
|
end
|
103
145
|
|
104
|
-
def
|
105
|
-
@pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger', :
|
146
|
+
def test_should_not_replace_an_existing_record_if_there_is_no_id_and_destroy_is_truthy
|
147
|
+
@pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger', :_destroy => '1' }
|
106
148
|
|
107
149
|
assert_equal @ship, @pirate.ship
|
108
150
|
assert_equal 'Nights Dirty Lightning', @pirate.ship.name
|
@@ -129,29 +171,29 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
|
|
129
171
|
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
|
130
172
|
end
|
131
173
|
|
132
|
-
def
|
174
|
+
def test_should_destroy_an_existing_record_if_there_is_a_matching_id_and_destroy_is_truthy
|
133
175
|
@pirate.ship.destroy
|
134
176
|
[1, '1', true, 'true'].each do |truth|
|
135
177
|
@pirate.reload.create_ship(:name => 'Mister Pablo')
|
136
178
|
assert_difference('Ship.count', -1) do
|
137
|
-
@pirate.update_attribute(:ship_attributes, { :id => @pirate.ship.id, :
|
179
|
+
@pirate.update_attribute(:ship_attributes, { :id => @pirate.ship.id, :_destroy => truth })
|
138
180
|
end
|
139
181
|
end
|
140
182
|
end
|
141
183
|
|
142
|
-
def
|
184
|
+
def test_should_not_destroy_an_existing_record_if_destroy_is_not_truthy
|
143
185
|
[nil, '0', 0, 'false', false].each do |not_truth|
|
144
186
|
assert_no_difference('Ship.count') do
|
145
|
-
@pirate.update_attribute(:ship_attributes, { :id => @pirate.ship.id, :
|
187
|
+
@pirate.update_attribute(:ship_attributes, { :id => @pirate.ship.id, :_destroy => not_truth })
|
146
188
|
end
|
147
189
|
end
|
148
190
|
end
|
149
191
|
|
150
|
-
def
|
192
|
+
def test_should_not_destroy_an_existing_record_if_allow_destroy_is_false
|
151
193
|
Pirate.accepts_nested_attributes_for :ship, :allow_destroy => false, :reject_if => proc { |attributes| attributes.empty? }
|
152
194
|
|
153
195
|
assert_no_difference('Ship.count') do
|
154
|
-
@pirate.update_attribute(:ship_attributes, { :id => @pirate.ship.id, :
|
196
|
+
@pirate.update_attribute(:ship_attributes, { :id => @pirate.ship.id, :_destroy => '1' })
|
155
197
|
end
|
156
198
|
|
157
199
|
Pirate.accepts_nested_attributes_for :ship, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
|
@@ -174,7 +216,7 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
|
|
174
216
|
|
175
217
|
def test_should_not_destroy_the_associated_model_until_the_parent_is_saved
|
176
218
|
assert_no_difference('Ship.count') do
|
177
|
-
@pirate.attributes = { :ship_attributes => { :id => @ship.id, :
|
219
|
+
@pirate.attributes = { :ship_attributes => { :id => @ship.id, :_destroy => '1' } }
|
178
220
|
end
|
179
221
|
assert_difference('Ship.count', -1) do
|
180
222
|
@pirate.save
|
@@ -205,9 +247,9 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
|
|
205
247
|
assert_equal 'Arr', @ship.pirate.catchphrase
|
206
248
|
end
|
207
249
|
|
208
|
-
def
|
250
|
+
def test_should_not_build_a_new_record_if_there_is_no_id_and_destroy_is_truthy
|
209
251
|
@pirate.destroy
|
210
|
-
@ship.reload.pirate_attributes = { :catchphrase => 'Arr', :
|
252
|
+
@ship.reload.pirate_attributes = { :catchphrase => 'Arr', :_destroy => '1' }
|
211
253
|
|
212
254
|
assert_nil @ship.pirate
|
213
255
|
end
|
@@ -227,8 +269,8 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
|
|
227
269
|
assert_equal 'Aye', @pirate.catchphrase
|
228
270
|
end
|
229
271
|
|
230
|
-
def
|
231
|
-
@ship.reload.pirate_attributes = { :catchphrase => 'Arr', :
|
272
|
+
def test_should_not_replace_an_existing_record_if_there_is_no_id_and_destroy_is_truthy
|
273
|
+
@ship.reload.pirate_attributes = { :catchphrase => 'Arr', :_destroy => '1' }
|
232
274
|
|
233
275
|
assert_equal @pirate, @ship.pirate
|
234
276
|
assert_equal 'Aye', @ship.pirate.catchphrase
|
@@ -255,29 +297,29 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
|
|
255
297
|
assert_equal 'Arr', @ship.pirate.catchphrase
|
256
298
|
end
|
257
299
|
|
258
|
-
def
|
300
|
+
def test_should_destroy_an_existing_record_if_there_is_a_matching_id_and_destroy_is_truthy
|
259
301
|
@ship.pirate.destroy
|
260
302
|
[1, '1', true, 'true'].each do |truth|
|
261
303
|
@ship.reload.create_pirate(:catchphrase => 'Arr')
|
262
304
|
assert_difference('Pirate.count', -1) do
|
263
|
-
@ship.update_attribute(:pirate_attributes, { :id => @ship.pirate.id, :
|
305
|
+
@ship.update_attribute(:pirate_attributes, { :id => @ship.pirate.id, :_destroy => truth })
|
264
306
|
end
|
265
307
|
end
|
266
308
|
end
|
267
309
|
|
268
|
-
def
|
310
|
+
def test_should_not_destroy_an_existing_record_if_destroy_is_not_truthy
|
269
311
|
[nil, '0', 0, 'false', false].each do |not_truth|
|
270
312
|
assert_no_difference('Pirate.count') do
|
271
|
-
@ship.update_attribute(:pirate_attributes, { :id => @ship.pirate.id, :
|
313
|
+
@ship.update_attribute(:pirate_attributes, { :id => @ship.pirate.id, :_destroy => not_truth })
|
272
314
|
end
|
273
315
|
end
|
274
316
|
end
|
275
317
|
|
276
|
-
def
|
318
|
+
def test_should_not_destroy_an_existing_record_if_allow_destroy_is_false
|
277
319
|
Ship.accepts_nested_attributes_for :pirate, :allow_destroy => false, :reject_if => proc { |attributes| attributes.empty? }
|
278
320
|
|
279
321
|
assert_no_difference('Pirate.count') do
|
280
|
-
@ship.update_attribute(:pirate_attributes, { :id => @ship.pirate.id, :
|
322
|
+
@ship.update_attribute(:pirate_attributes, { :id => @ship.pirate.id, :_destroy => '1' })
|
281
323
|
end
|
282
324
|
|
283
325
|
Ship.accepts_nested_attributes_for :pirate, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
|
@@ -293,7 +335,7 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
|
|
293
335
|
|
294
336
|
def test_should_not_destroy_the_associated_model_until_the_parent_is_saved
|
295
337
|
assert_no_difference('Pirate.count') do
|
296
|
-
@ship.attributes = { :pirate_attributes => { :id => @ship.pirate.id, '
|
338
|
+
@ship.attributes = { :pirate_attributes => { :id => @ship.pirate.id, '_destroy' => true } }
|
297
339
|
end
|
298
340
|
assert_difference('Pirate.count', -1) { @ship.save }
|
299
341
|
end
|
@@ -361,18 +403,18 @@ module NestedAttributesOnACollectionAssociationTests
|
|
361
403
|
assert_equal 'Privateers Greed', @pirate.send(@association_name).last.name
|
362
404
|
end
|
363
405
|
|
364
|
-
def
|
406
|
+
def test_should_not_assign_destroy_key_to_a_record
|
365
407
|
assert_nothing_raised ActiveRecord::UnknownAttributeError do
|
366
|
-
@pirate.send(association_setter, { 'foo' => { '
|
408
|
+
@pirate.send(association_setter, { 'foo' => { '_destroy' => '0' }})
|
367
409
|
end
|
368
410
|
end
|
369
411
|
|
370
|
-
def
|
412
|
+
def test_should_ignore_new_associated_records_with_truthy_destroy_attribute
|
371
413
|
@pirate.send(@association_name).destroy_all
|
372
414
|
@pirate.reload.attributes = {
|
373
415
|
association_getter => {
|
374
416
|
'foo' => { :name => 'Grace OMalley' },
|
375
|
-
'bar' => { :name => 'Privateers Greed', '
|
417
|
+
'bar' => { :name => 'Privateers Greed', '_destroy' => '1' }
|
376
418
|
}
|
377
419
|
}
|
378
420
|
|
@@ -424,7 +466,7 @@ module NestedAttributesOnACollectionAssociationTests
|
|
424
466
|
['1', 1, 'true', true].each do |true_variable|
|
425
467
|
record = @pirate.reload.send(@association_name).create!(:name => 'Grace OMalley')
|
426
468
|
@pirate.send(association_setter,
|
427
|
-
@alternate_params[association_getter].merge('baz' => { :id => record.id, '
|
469
|
+
@alternate_params[association_getter].merge('baz' => { :id => record.id, '_destroy' => true_variable })
|
428
470
|
)
|
429
471
|
|
430
472
|
assert_difference('@pirate.send(@association_name).count', -1) do
|
@@ -435,7 +477,7 @@ module NestedAttributesOnACollectionAssociationTests
|
|
435
477
|
|
436
478
|
def test_should_not_destroy_the_associated_model_with_a_non_truthy_argument
|
437
479
|
[nil, '', '0', 0, 'false', false].each do |false_variable|
|
438
|
-
@alternate_params[association_getter]['foo']['
|
480
|
+
@alternate_params[association_getter]['foo']['_destroy'] = false_variable
|
439
481
|
assert_no_difference('@pirate.send(@association_name).count') do
|
440
482
|
@pirate.update_attributes(@alternate_params)
|
441
483
|
end
|
@@ -444,7 +486,7 @@ module NestedAttributesOnACollectionAssociationTests
|
|
444
486
|
|
445
487
|
def test_should_not_destroy_the_associated_model_until_the_parent_is_saved
|
446
488
|
assert_no_difference('@pirate.send(@association_name).count') do
|
447
|
-
@pirate.send(association_setter, @alternate_params[association_getter].merge('baz' => { :id => @child_1.id, '
|
489
|
+
@pirate.send(association_setter, @alternate_params[association_getter].merge('baz' => { :id => @child_1.id, '_destroy' => true }))
|
448
490
|
end
|
449
491
|
assert_difference('@pirate.send(@association_name).count', -1) { @pirate.save }
|
450
492
|
end
|
@@ -507,3 +549,33 @@ class TestNestedAttributesOnAHasAndBelongsToManyAssociation < ActiveRecord::Test
|
|
507
549
|
|
508
550
|
include NestedAttributesOnACollectionAssociationTests
|
509
551
|
end
|
552
|
+
|
553
|
+
class TestNestedAttributesLimit < ActiveRecord::TestCase
|
554
|
+
def setup
|
555
|
+
Pirate.accepts_nested_attributes_for :parrots, :limit => 2
|
556
|
+
|
557
|
+
@pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
558
|
+
end
|
559
|
+
|
560
|
+
def teardown
|
561
|
+
Pirate.accepts_nested_attributes_for :parrots, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
|
562
|
+
end
|
563
|
+
|
564
|
+
def test_limit_with_less_records
|
565
|
+
@pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Big Big Love' } } }
|
566
|
+
assert_difference('Parrot.count') { @pirate.save! }
|
567
|
+
end
|
568
|
+
|
569
|
+
def test_limit_with_number_exact_records
|
570
|
+
@pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Lovely Day' }, 'bar' => { :name => 'Blown Away' } } }
|
571
|
+
assert_difference('Parrot.count', 2) { @pirate.save! }
|
572
|
+
end
|
573
|
+
|
574
|
+
def test_limit_with_exceeding_records
|
575
|
+
assert_raises(ActiveRecord::NestedAttributes::TooManyRecords) do
|
576
|
+
@pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Lovely Day' },
|
577
|
+
'bar' => { :name => 'Blown Away' },
|
578
|
+
'car' => { :name => 'The Happening' }} }
|
579
|
+
end
|
580
|
+
end
|
581
|
+
end
|
@@ -170,9 +170,9 @@ class ReflectionTest < ActiveRecord::TestCase
|
|
170
170
|
|
171
171
|
def test_reflection_of_all_associations
|
172
172
|
# FIXME these assertions bust a lot
|
173
|
-
assert_equal
|
174
|
-
assert_equal
|
175
|
-
assert_equal
|
173
|
+
assert_equal 36, Firm.reflect_on_all_associations.size
|
174
|
+
assert_equal 26, Firm.reflect_on_all_associations(:has_many).size
|
175
|
+
assert_equal 10, Firm.reflect_on_all_associations(:has_one).size
|
176
176
|
assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size
|
177
177
|
end
|
178
178
|
|
@@ -651,6 +651,14 @@ class ActiveRecordErrorI18nTests < ActiveSupport::TestCase
|
|
651
651
|
assert_full_message 'Title is kaputt?!', :title, :kaputt, :message => :broken
|
652
652
|
end
|
653
653
|
|
654
|
+
test "#full_message with different scope" do
|
655
|
+
store_translations(:my_errors => { :messages => { :kaputt => 'is kaputt' } })
|
656
|
+
assert_full_message 'Title is kaputt', :title, :kaputt, :scope => [:activerecord, :my_errors]
|
657
|
+
|
658
|
+
store_translations(:my_errors => { :full_messages => { :kaputt => '{{attribute}} {{message}}!' } })
|
659
|
+
assert_full_message 'Title is kaputt!', :title, :kaputt, :scope => [:activerecord, :my_errors]
|
660
|
+
end
|
661
|
+
|
654
662
|
# switch locales
|
655
663
|
|
656
664
|
test "#message allows to switch locales" do
|
@@ -28,6 +28,12 @@ class ProtectedPerson < ActiveRecord::Base
|
|
28
28
|
set_table_name 'people'
|
29
29
|
attr_accessor :addon
|
30
30
|
attr_protected :first_name
|
31
|
+
|
32
|
+
def special_error
|
33
|
+
this_method_does_not_exist!
|
34
|
+
rescue
|
35
|
+
errors.add(:special_error, "This method does not exist")
|
36
|
+
end
|
31
37
|
end
|
32
38
|
|
33
39
|
class UniqueReply < Reply
|
@@ -172,6 +178,14 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
172
178
|
end
|
173
179
|
end
|
174
180
|
|
181
|
+
def test_values_are_not_retrieved_unless_needed
|
182
|
+
assert_nothing_raised do
|
183
|
+
person = ProtectedPerson.new
|
184
|
+
person.special_error
|
185
|
+
assert_equal "This method does not exist", person.errors[:special_error]
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
175
189
|
def test_single_error_per_attr_iteration
|
176
190
|
r = Reply.new
|
177
191
|
r.save
|
@@ -905,14 +919,18 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
905
919
|
end
|
906
920
|
|
907
921
|
def test_validates_length_with_globally_modified_error_message
|
908
|
-
ActiveSupport::Deprecation.silence
|
909
|
-
|
910
|
-
|
922
|
+
defaults = ActiveSupport::Deprecation.silence { ActiveRecord::Errors.default_error_messages }
|
923
|
+
original_message = defaults[:too_short]
|
924
|
+
defaults[:too_short] = 'tu est trops petit hombre {{count}}'
|
925
|
+
|
911
926
|
Topic.validates_length_of :title, :minimum => 10
|
912
927
|
t = Topic.create(:title => 'too short')
|
913
928
|
assert !t.valid?
|
914
929
|
|
915
930
|
assert_equal 'tu est trops petit hombre 10', t.errors['title']
|
931
|
+
|
932
|
+
ensure
|
933
|
+
defaults[:too_short] = original_message
|
916
934
|
end
|
917
935
|
|
918
936
|
def test_validates_size_of_association
|
@@ -1432,12 +1450,22 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1432
1450
|
end
|
1433
1451
|
|
1434
1452
|
def test_validation_order
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
1453
|
+
Topic.validates_presence_of :title, :author_name
|
1454
|
+
Topic.validate {|topic| topic.errors.add('author_email_address', 'will never be valid')}
|
1455
|
+
Topic.validates_length_of :title, :content, :minimum => 2
|
1456
|
+
|
1457
|
+
t = Topic.new :title => ''
|
1458
|
+
t.valid?
|
1459
|
+
e = t.errors.instance_variable_get '@errors'
|
1460
|
+
assert_equal 'title', key = e.keys.first
|
1461
|
+
assert_equal "can't be blank", t.errors.on(key).first
|
1462
|
+
assert_equal 'is too short (minimum is 2 characters)', t.errors.on(key).second
|
1463
|
+
assert_equal 'author_name', key = e.keys.second
|
1464
|
+
assert_equal "can't be blank", t.errors.on(key)
|
1465
|
+
assert_equal 'author_email_address', key = e.keys.third
|
1466
|
+
assert_equal 'will never be valid', t.errors.on(key)
|
1467
|
+
assert_equal 'content', key = e.keys.fourth
|
1468
|
+
assert_equal 'is too short (minimum is 2 characters)', t.errors.on(key)
|
1441
1469
|
end
|
1442
1470
|
|
1443
1471
|
def test_invalid_should_be_the_opposite_of_valid
|