activerecord 2.2.3 → 2.3.2
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 +438 -396
- data/Rakefile +4 -2
- data/lib/active_record.rb +46 -43
- data/lib/active_record/association_preload.rb +34 -19
- data/lib/active_record/associations.rb +193 -251
- data/lib/active_record/associations/association_collection.rb +38 -21
- data/lib/active_record/associations/association_proxy.rb +11 -4
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +2 -2
- data/lib/active_record/associations/has_many_association.rb +2 -2
- data/lib/active_record/associations/has_many_through_association.rb +8 -8
- data/lib/active_record/associations/has_one_association.rb +11 -2
- data/lib/active_record/attribute_methods.rb +1 -0
- data/lib/active_record/autosave_association.rb +349 -0
- data/lib/active_record/base.rb +292 -106
- data/lib/active_record/batches.rb +73 -0
- data/lib/active_record/calculations.rb +34 -16
- data/lib/active_record/callbacks.rb +37 -8
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +16 -0
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +3 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +103 -15
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +6 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +28 -25
- data/lib/active_record/connection_adapters/abstract_adapter.rb +29 -5
- data/lib/active_record/connection_adapters/mysql_adapter.rb +50 -21
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +26 -41
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +41 -21
- data/lib/active_record/dirty.rb +1 -1
- data/lib/active_record/dynamic_scope_match.rb +25 -0
- data/lib/active_record/fixtures.rb +193 -198
- data/lib/active_record/locale/en.yml +1 -1
- data/lib/active_record/locking/optimistic.rb +33 -0
- data/lib/active_record/migration.rb +8 -2
- data/lib/active_record/named_scope.rb +13 -6
- data/lib/active_record/nested_attributes.rb +329 -0
- data/lib/active_record/query_cache.rb +25 -13
- data/lib/active_record/reflection.rb +6 -1
- data/lib/active_record/schema_dumper.rb +2 -0
- data/lib/active_record/serialization.rb +3 -1
- data/lib/active_record/serializers/json_serializer.rb +19 -0
- data/lib/active_record/serializers/xml_serializer.rb +28 -13
- data/lib/active_record/session_store.rb +318 -0
- data/lib/active_record/test_case.rb +15 -9
- data/lib/active_record/timestamp.rb +2 -2
- data/lib/active_record/transactions.rb +58 -8
- data/lib/active_record/validations.rb +29 -24
- data/lib/active_record/version.rb +2 -2
- data/test/cases/ar_schema_test.rb +0 -1
- data/test/cases/associations/belongs_to_associations_test.rb +35 -131
- data/test/cases/associations/cascaded_eager_loading_test.rb +8 -0
- data/test/cases/associations/eager_load_nested_include_test.rb +29 -0
- data/test/cases/associations/eager_test.rb +137 -7
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +45 -7
- data/test/cases/associations/has_many_associations_test.rb +110 -149
- data/test/cases/associations/has_many_through_associations_test.rb +39 -7
- data/test/cases/associations/has_one_associations_test.rb +39 -92
- data/test/cases/associations/has_one_through_associations_test.rb +34 -3
- data/test/cases/associations/inner_join_association_test.rb +0 -5
- data/test/cases/associations/join_model_test.rb +5 -7
- data/test/cases/attribute_methods_test.rb +13 -1
- data/test/cases/autosave_association_test.rb +901 -0
- data/test/cases/base_test.rb +41 -21
- data/test/cases/batches_test.rb +61 -0
- data/test/cases/calculations_test.rb +37 -17
- data/test/cases/callbacks_test.rb +43 -5
- data/test/cases/connection_pool_test.rb +25 -0
- data/test/cases/copy_table_test_sqlite.rb +11 -0
- data/test/cases/datatype_test_postgresql.rb +1 -0
- data/test/cases/defaults_test.rb +37 -26
- data/test/cases/dirty_test.rb +26 -2
- data/test/cases/finder_test.rb +79 -44
- data/test/cases/fixtures_test.rb +15 -19
- data/test/cases/helper.rb +26 -19
- data/test/cases/inheritance_test.rb +2 -2
- data/test/cases/json_serialization_test.rb +1 -1
- data/test/cases/locking_test.rb +23 -5
- data/test/cases/method_scoping_test.rb +126 -3
- data/test/cases/migration_test.rb +253 -237
- data/test/cases/named_scope_test.rb +73 -3
- data/test/cases/nested_attributes_test.rb +509 -0
- data/test/cases/query_cache_test.rb +0 -4
- data/test/cases/reflection_test.rb +13 -3
- data/test/cases/reload_models_test.rb +3 -1
- data/test/cases/repair_helper.rb +50 -0
- data/test/cases/schema_dumper_test.rb +0 -1
- data/test/cases/transactions_test.rb +177 -12
- data/test/cases/validations_i18n_test.rb +288 -294
- data/test/cases/validations_test.rb +230 -180
- data/test/cases/xml_serialization_test.rb +19 -1
- data/test/fixtures/fixture_database.sqlite3 +0 -0
- data/test/fixtures/fixture_database_2.sqlite3 +0 -0
- data/test/fixtures/member_types.yml +6 -0
- data/test/fixtures/members.yml +3 -1
- data/test/fixtures/people.yml +10 -1
- data/test/fixtures/toys.yml +4 -0
- data/test/models/author.rb +1 -2
- data/test/models/bird.rb +3 -0
- data/test/models/category.rb +1 -0
- data/test/models/company.rb +3 -0
- data/test/models/developer.rb +12 -0
- data/test/models/event.rb +3 -0
- data/test/models/member.rb +1 -0
- data/test/models/member_detail.rb +1 -0
- data/test/models/member_type.rb +3 -0
- data/test/models/owner.rb +2 -1
- data/test/models/parrot.rb +2 -0
- data/test/models/person.rb +6 -0
- data/test/models/pet.rb +2 -1
- data/test/models/pirate.rb +55 -1
- data/test/models/post.rb +6 -0
- data/test/models/project.rb +1 -0
- data/test/models/reply.rb +6 -0
- data/test/models/ship.rb +8 -1
- data/test/models/ship_part.rb +5 -0
- data/test/models/topic.rb +13 -1
- data/test/models/toy.rb +4 -0
- data/test/schema/schema.rb +35 -2
- metadata +70 -9
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
@@ -55,8 +55,6 @@ class QueryCacheTest < ActiveRecord::TestCase
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
uses_mocha 'QueryCacheExpiryTest' do
|
59
|
-
|
60
58
|
class QueryCacheExpiryTest < ActiveRecord::TestCase
|
61
59
|
fixtures :tasks, :posts, :categories, :categories_posts
|
62
60
|
|
@@ -123,5 +121,3 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
|
|
123
121
|
end
|
124
122
|
end
|
125
123
|
end
|
126
|
-
|
127
|
-
end
|
@@ -4,6 +4,7 @@ require 'models/customer'
|
|
4
4
|
require 'models/company'
|
5
5
|
require 'models/company_in_module'
|
6
6
|
require 'models/subscriber'
|
7
|
+
require 'models/pirate'
|
7
8
|
|
8
9
|
class ReflectionTest < ActiveRecord::TestCase
|
9
10
|
fixtures :topics, :customers, :companies, :subscribers
|
@@ -91,6 +92,15 @@ class ReflectionTest < ActiveRecord::TestCase
|
|
91
92
|
assert_equal Money, Customer.reflect_on_aggregation(:balance).klass
|
92
93
|
end
|
93
94
|
|
95
|
+
def test_reflect_on_all_autosave_associations
|
96
|
+
expected = Pirate.reflect_on_all_associations.select { |r| r.options[:autosave] }
|
97
|
+
received = Pirate.reflect_on_all_autosave_associations
|
98
|
+
|
99
|
+
assert !received.empty?
|
100
|
+
assert_not_equal Pirate.reflect_on_all_associations.length, received.length
|
101
|
+
assert_equal expected, received
|
102
|
+
end
|
103
|
+
|
94
104
|
def test_has_many_reflection
|
95
105
|
reflection_for_clients = ActiveRecord::Reflection::AssociationReflection.new(:has_many, :clients, { :order => "id", :dependent => :destroy }, Firm)
|
96
106
|
|
@@ -160,9 +170,9 @@ class ReflectionTest < ActiveRecord::TestCase
|
|
160
170
|
|
161
171
|
def test_reflection_of_all_associations
|
162
172
|
# FIXME these assertions bust a lot
|
163
|
-
assert_equal
|
164
|
-
assert_equal
|
165
|
-
assert_equal
|
173
|
+
assert_equal 28, Firm.reflect_on_all_associations.size
|
174
|
+
assert_equal 21, Firm.reflect_on_all_associations(:has_many).size
|
175
|
+
assert_equal 7, Firm.reflect_on_all_associations(:has_one).size
|
166
176
|
assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size
|
167
177
|
end
|
168
178
|
|
@@ -3,6 +3,8 @@ require 'models/owner'
|
|
3
3
|
require 'models/pet'
|
4
4
|
|
5
5
|
class ReloadModelsTest < ActiveRecord::TestCase
|
6
|
+
fixtures :pets
|
7
|
+
|
6
8
|
def test_has_one_with_reload
|
7
9
|
pet = Pet.find_by_name('parrot')
|
8
10
|
pet.owner = Owner.find_by_name('ashley')
|
@@ -17,4 +19,4 @@ class ReloadModelsTest < ActiveRecord::TestCase
|
|
17
19
|
pet.owner = Owner.find_by_name('ashley')
|
18
20
|
assert_equal pet.owner, Owner.find_by_name('ashley')
|
19
21
|
end
|
20
|
-
end
|
22
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Testing
|
3
|
+
module RepairHelper
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
extend ClassMethods
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module Toolbox
|
11
|
+
def self.record_validations(*model_classes)
|
12
|
+
model_classes.inject({}) do |repair, klass|
|
13
|
+
repair[klass] ||= {}
|
14
|
+
[:validate, :validate_on_create, :validate_on_update].each do |callback|
|
15
|
+
the_callback = klass.instance_variable_get("@#{callback.to_s}_callbacks")
|
16
|
+
repair[klass][callback] = (the_callback.nil? ? nil : the_callback.dup)
|
17
|
+
end
|
18
|
+
repair
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.reset_validations(recorded)
|
23
|
+
recorded.each do |klass, repairs|
|
24
|
+
[:validate, :validate_on_create, :validate_on_update].each do |callback|
|
25
|
+
klass.instance_variable_set("@#{callback.to_s}_callbacks", repairs[callback])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module ClassMethods
|
32
|
+
def repair_validations(*model_classes)
|
33
|
+
setup do
|
34
|
+
@validation_repairs = ActiveRecord::Testing::RepairHelper::Toolbox.record_validations(*model_classes)
|
35
|
+
end
|
36
|
+
teardown do
|
37
|
+
ActiveRecord::Testing::RepairHelper::Toolbox.reset_validations(@validation_repairs)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def repair_validations(*model_classes, &block)
|
43
|
+
validation_repairs = ActiveRecord::Testing::RepairHelper::Toolbox.record_validations(*model_classes)
|
44
|
+
return block.call
|
45
|
+
ensure
|
46
|
+
ActiveRecord::Testing::RepairHelper::Toolbox.reset_validations(validation_repairs)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -213,22 +213,143 @@ class TransactionTest < ActiveRecord::TestCase
|
|
213
213
|
assert Topic.find(2).approved?, "Second should still be approved"
|
214
214
|
end
|
215
215
|
|
216
|
-
|
217
|
-
|
218
|
-
Topic.
|
219
|
-
|
220
|
-
|
221
|
-
|
216
|
+
def test_invalid_keys_for_transaction
|
217
|
+
assert_raise ArgumentError do
|
218
|
+
Topic.transaction :nested => true do
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def test_force_savepoint_in_nested_transaction
|
224
|
+
Topic.transaction do
|
225
|
+
@first.approved = true
|
226
|
+
@second.approved = false
|
227
|
+
@first.save!
|
228
|
+
@second.save!
|
222
229
|
|
230
|
+
begin
|
231
|
+
Topic.transaction :requires_new => true do
|
232
|
+
@first.happy = false
|
233
|
+
@first.save!
|
234
|
+
raise
|
235
|
+
end
|
236
|
+
rescue
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
assert @first.reload.approved?
|
241
|
+
assert !@second.reload.approved?
|
242
|
+
end if Topic.connection.supports_savepoints?
|
243
|
+
|
244
|
+
def test_no_savepoint_in_nested_transaction_without_force
|
245
|
+
Topic.transaction do
|
246
|
+
@first.approved = true
|
247
|
+
@second.approved = false
|
248
|
+
@first.save!
|
249
|
+
@second.save!
|
250
|
+
|
251
|
+
begin
|
252
|
+
Topic.transaction do
|
253
|
+
@first.approved = false
|
254
|
+
@first.save!
|
255
|
+
raise
|
256
|
+
end
|
257
|
+
rescue
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
assert !@first.reload.approved?
|
262
|
+
assert !@second.reload.approved?
|
263
|
+
end if Topic.connection.supports_savepoints?
|
264
|
+
|
265
|
+
def test_many_savepoints
|
266
|
+
Topic.transaction do
|
267
|
+
@first.content = "One"
|
268
|
+
@first.save!
|
269
|
+
|
270
|
+
begin
|
271
|
+
Topic.transaction :requires_new => true do
|
272
|
+
@first.content = "Two"
|
273
|
+
@first.save!
|
274
|
+
|
275
|
+
begin
|
276
|
+
Topic.transaction :requires_new => true do
|
277
|
+
@first.content = "Three"
|
278
|
+
@first.save!
|
279
|
+
|
280
|
+
begin
|
281
|
+
Topic.transaction :requires_new => true do
|
282
|
+
@first.content = "Four"
|
283
|
+
@first.save!
|
284
|
+
raise
|
285
|
+
end
|
286
|
+
rescue
|
287
|
+
end
|
288
|
+
|
289
|
+
@three = @first.reload.content
|
290
|
+
raise
|
291
|
+
end
|
292
|
+
rescue
|
293
|
+
end
|
294
|
+
|
295
|
+
@two = @first.reload.content
|
296
|
+
raise
|
297
|
+
end
|
298
|
+
rescue
|
299
|
+
end
|
300
|
+
|
301
|
+
@one = @first.reload.content
|
302
|
+
end
|
303
|
+
|
304
|
+
assert_equal "One", @one
|
305
|
+
assert_equal "Two", @two
|
306
|
+
assert_equal "Three", @three
|
307
|
+
end if Topic.connection.supports_savepoints?
|
308
|
+
|
309
|
+
def test_rollback_when_commit_raises
|
310
|
+
Topic.connection.expects(:begin_db_transaction)
|
311
|
+
Topic.connection.expects(:commit_db_transaction).raises('OH NOES')
|
312
|
+
Topic.connection.expects(:outside_transaction?).returns(false)
|
313
|
+
Topic.connection.expects(:rollback_db_transaction)
|
314
|
+
|
315
|
+
assert_raise RuntimeError do
|
316
|
+
Topic.transaction do
|
317
|
+
# do nothing
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
if current_adapter?(:PostgreSQLAdapter) && defined?(PGconn::PQTRANS_IDLE)
|
323
|
+
def test_outside_transaction_works
|
324
|
+
assert Topic.connection.outside_transaction?
|
325
|
+
Topic.connection.begin_db_transaction
|
326
|
+
assert !Topic.connection.outside_transaction?
|
327
|
+
Topic.connection.rollback_db_transaction
|
328
|
+
assert Topic.connection.outside_transaction?
|
329
|
+
end
|
330
|
+
|
331
|
+
def test_rollback_wont_be_executed_if_no_transaction_active
|
223
332
|
assert_raise RuntimeError do
|
224
333
|
Topic.transaction do
|
225
|
-
|
334
|
+
Topic.connection.rollback_db_transaction
|
335
|
+
Topic.connection.expects(:rollback_db_transaction).never
|
336
|
+
raise "Rails doesn't scale!"
|
226
337
|
end
|
227
338
|
end
|
228
339
|
end
|
340
|
+
|
341
|
+
def test_open_transactions_count_is_reset_to_zero_if_no_transaction_active
|
342
|
+
Topic.transaction do
|
343
|
+
Topic.transaction do
|
344
|
+
Topic.connection.rollback_db_transaction
|
345
|
+
end
|
346
|
+
assert_equal 0, Topic.connection.open_transactions
|
347
|
+
end
|
348
|
+
assert_equal 0, Topic.connection.open_transactions
|
349
|
+
end
|
229
350
|
end
|
230
351
|
|
231
|
-
def
|
352
|
+
def test_sqlite_add_column_in_transaction
|
232
353
|
return true unless current_adapter?(:SQLite3Adapter, :SQLiteAdapter)
|
233
354
|
|
234
355
|
# Test first if column creation/deletion works correctly when no
|
@@ -247,10 +368,15 @@ class TransactionTest < ActiveRecord::TestCase
|
|
247
368
|
assert !Topic.column_names.include?('stuff')
|
248
369
|
end
|
249
370
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
371
|
+
if Topic.connection.supports_ddl_transactions?
|
372
|
+
assert_nothing_raised do
|
373
|
+
Topic.transaction { Topic.connection.add_column('topics', 'stuff', :string) }
|
374
|
+
end
|
375
|
+
else
|
376
|
+
Topic.transaction do
|
377
|
+
assert_raise(ActiveRecord::StatementInvalid) { Topic.connection.add_column('topics', 'stuff', :string) }
|
378
|
+
raise ActiveRecord::Rollback
|
379
|
+
end
|
254
380
|
end
|
255
381
|
end
|
256
382
|
|
@@ -282,6 +408,45 @@ class TransactionTest < ActiveRecord::TestCase
|
|
282
408
|
end
|
283
409
|
end
|
284
410
|
|
411
|
+
class TransactionsWithTransactionalFixturesTest < ActiveRecord::TestCase
|
412
|
+
self.use_transactional_fixtures = true
|
413
|
+
fixtures :topics
|
414
|
+
|
415
|
+
def test_automatic_savepoint_in_outer_transaction
|
416
|
+
@first = Topic.find(1)
|
417
|
+
|
418
|
+
begin
|
419
|
+
Topic.transaction do
|
420
|
+
@first.approved = true
|
421
|
+
@first.save!
|
422
|
+
raise
|
423
|
+
end
|
424
|
+
rescue
|
425
|
+
assert !@first.reload.approved?
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
def test_no_automatic_savepoint_for_inner_transaction
|
430
|
+
@first = Topic.find(1)
|
431
|
+
|
432
|
+
Topic.transaction do
|
433
|
+
@first.approved = true
|
434
|
+
@first.save!
|
435
|
+
|
436
|
+
begin
|
437
|
+
Topic.transaction do
|
438
|
+
@first.approved = false
|
439
|
+
@first.save!
|
440
|
+
raise
|
441
|
+
end
|
442
|
+
rescue
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
assert !@first.reload.approved?
|
447
|
+
end
|
448
|
+
end if Topic.connection.supports_savepoints?
|
449
|
+
|
285
450
|
if current_adapter?(:PostgreSQLAdapter)
|
286
451
|
class ConcurrentTransactionTest < TransactionTest
|
287
452
|
use_concurrent_connections
|
@@ -2,7 +2,7 @@ require "cases/helper"
|
|
2
2
|
require 'models/topic'
|
3
3
|
require 'models/reply'
|
4
4
|
|
5
|
-
class ActiveRecordValidationsI18nTests <
|
5
|
+
class ActiveRecordValidationsI18nTests < ActiveSupport::TestCase
|
6
6
|
def setup
|
7
7
|
reset_callbacks Topic
|
8
8
|
@topic = Topic.new
|
@@ -71,359 +71,353 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase
|
|
71
71
|
end
|
72
72
|
|
73
73
|
# ActiveRecord::Errors
|
74
|
-
|
74
|
+
def test_errors_generate_message_translates_custom_model_attribute_key
|
75
75
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
:
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
}
|
84
|
-
).returns('Topic')
|
76
|
+
I18n.expects(:translate).with(
|
77
|
+
:topic,
|
78
|
+
{ :count => 1,
|
79
|
+
:default => ['Topic'],
|
80
|
+
:scope => [:activerecord, :models]
|
81
|
+
}
|
82
|
+
).returns('Topic')
|
85
83
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
84
|
+
I18n.expects(:translate).with(
|
85
|
+
:"topic.title",
|
86
|
+
{ :count => 1,
|
87
|
+
:default => ['Title'],
|
88
|
+
:scope => [:activerecord, :attributes]
|
89
|
+
}
|
90
|
+
).returns('Title')
|
91
|
+
|
92
|
+
I18n.expects(:translate).with(
|
93
|
+
:"models.topic.attributes.title.invalid",
|
94
|
+
:value => nil,
|
95
|
+
:scope => [:activerecord, :errors],
|
96
|
+
:default => [
|
97
|
+
:"models.topic.invalid",
|
98
|
+
'default from class def error 1',
|
99
|
+
:"messages.invalid"],
|
100
|
+
:attribute => "Title",
|
101
|
+
:model => "Topic"
|
102
|
+
).returns('default from class def error 1')
|
103
|
+
|
104
|
+
@topic.errors.generate_message :title, :invalid, :default => 'default from class def error 1'
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_errors_generate_message_translates_custom_model_attribute_keys_with_sti
|
108
|
+
|
109
|
+
I18n.expects(:translate).with(
|
110
|
+
:reply,
|
111
|
+
{ :count => 1,
|
112
|
+
:default => [:topic, 'Reply'],
|
113
|
+
:scope => [:activerecord, :models]
|
114
|
+
}
|
115
|
+
).returns('Reply')
|
93
116
|
|
94
|
-
|
117
|
+
I18n.expects(:translate).with(
|
118
|
+
:"reply.title",
|
119
|
+
{ :count => 1,
|
120
|
+
:default => [:'topic.title', 'Title'],
|
121
|
+
:scope => [:activerecord, :attributes]
|
122
|
+
}
|
123
|
+
).returns('Title')
|
124
|
+
|
125
|
+
I18n.expects(:translate).with(
|
126
|
+
:"models.reply.attributes.title.invalid",
|
127
|
+
:value => nil,
|
128
|
+
:scope => [:activerecord, :errors],
|
129
|
+
:default => [
|
130
|
+
:"models.reply.invalid",
|
95
131
|
:"models.topic.attributes.title.invalid",
|
96
|
-
:
|
97
|
-
|
98
|
-
:
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
:attribute => "Title",
|
103
|
-
:model => "Topic"
|
104
|
-
).returns('default from class def error 1')
|
105
|
-
|
106
|
-
@topic.errors.generate_message :title, :invalid, :default => 'default from class def error 1'
|
107
|
-
end
|
108
|
-
|
109
|
-
def test_errors_generate_message_translates_custom_model_attribute_keys_with_sti
|
110
|
-
|
111
|
-
I18n.expects(:translate).with(
|
112
|
-
:reply,
|
113
|
-
{ :count => 1,
|
114
|
-
:default => [:topic, 'Reply'],
|
115
|
-
:scope => [:activerecord, :models]
|
116
|
-
}
|
117
|
-
).returns('Reply')
|
132
|
+
:"models.topic.invalid",
|
133
|
+
'default from class def',
|
134
|
+
:"messages.invalid"],
|
135
|
+
:model => 'Reply',
|
136
|
+
:attribute => 'Title'
|
137
|
+
).returns("default from class def")
|
118
138
|
|
119
|
-
|
120
|
-
:"reply.title",
|
121
|
-
{ :count => 1,
|
122
|
-
:default => [:'topic.title', 'Title'],
|
123
|
-
:scope => [:activerecord, :attributes]
|
124
|
-
}
|
125
|
-
).returns('Title')
|
126
|
-
|
127
|
-
I18n.expects(:translate).with(
|
128
|
-
:"models.reply.attributes.title.invalid",
|
129
|
-
:value => nil,
|
130
|
-
:scope => [:activerecord, :errors],
|
131
|
-
:default => [
|
132
|
-
:"models.reply.invalid",
|
133
|
-
:"models.topic.attributes.title.invalid",
|
134
|
-
:"models.topic.invalid",
|
135
|
-
'default from class def',
|
136
|
-
:"messages.invalid"],
|
137
|
-
:model => 'Reply',
|
138
|
-
:attribute => 'Title'
|
139
|
-
).returns("default from class def")
|
140
|
-
|
141
|
-
Reply.new.errors.generate_message :title, :invalid, :default => 'default from class def'
|
139
|
+
Reply.new.errors.generate_message :title, :invalid, :default => 'default from class def'
|
142
140
|
|
143
|
-
|
141
|
+
end
|
144
142
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
143
|
+
def test_errors_add_on_empty_generates_message
|
144
|
+
@topic.errors.expects(:generate_message).with(:title, :empty, {:default => nil})
|
145
|
+
@topic.errors.add_on_empty :title
|
146
|
+
end
|
149
147
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
148
|
+
def test_errors_add_on_empty_generates_message_with_custom_default_message
|
149
|
+
@topic.errors.expects(:generate_message).with(:title, :empty, {:default => 'custom'})
|
150
|
+
@topic.errors.add_on_empty :title, 'custom'
|
151
|
+
end
|
154
152
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
153
|
+
def test_errors_add_on_blank_generates_message
|
154
|
+
@topic.errors.expects(:generate_message).with(:title, :blank, {:default => nil})
|
155
|
+
@topic.errors.add_on_blank :title
|
156
|
+
end
|
159
157
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
158
|
+
def test_errors_add_on_blank_generates_message_with_custom_default_message
|
159
|
+
@topic.errors.expects(:generate_message).with(:title, :blank, {:default => 'custom'})
|
160
|
+
@topic.errors.add_on_blank :title, 'custom'
|
161
|
+
end
|
164
162
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
end
|
163
|
+
def test_errors_full_messages_translates_human_attribute_name_for_model_attributes
|
164
|
+
@topic.errors.instance_variable_set :@errors, { 'title' => ['empty'] }
|
165
|
+
I18n.expects(:translate).with(:"topic.title", :default => ['Title'], :scope => [:activerecord, :attributes], :count => 1).returns('Title')
|
166
|
+
@topic.errors.full_messages :locale => 'en'
|
170
167
|
end
|
171
168
|
|
172
169
|
# ActiveRecord::Validations
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
@topic.valid?
|
181
|
-
end
|
170
|
+
# validates_confirmation_of w/ mocha
|
171
|
+
def test_validates_confirmation_of_generates_message
|
172
|
+
Topic.validates_confirmation_of :title
|
173
|
+
@topic.title_confirmation = 'foo'
|
174
|
+
@topic.errors.expects(:generate_message).with(:title, :confirmation, {:default => nil})
|
175
|
+
@topic.valid?
|
176
|
+
end
|
182
177
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
178
|
+
def test_validates_confirmation_of_generates_message_with_custom_default_message
|
179
|
+
Topic.validates_confirmation_of :title, :message => 'custom'
|
180
|
+
@topic.title_confirmation = 'foo'
|
181
|
+
@topic.errors.expects(:generate_message).with(:title, :confirmation, {:default => 'custom'})
|
182
|
+
@topic.valid?
|
183
|
+
end
|
189
184
|
|
190
|
-
|
185
|
+
# validates_acceptance_of w/ mocha
|
191
186
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
187
|
+
def test_validates_acceptance_of_generates_message
|
188
|
+
Topic.validates_acceptance_of :title, :allow_nil => false
|
189
|
+
@topic.errors.expects(:generate_message).with(:title, :accepted, {:default => nil})
|
190
|
+
@topic.valid?
|
191
|
+
end
|
197
192
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
193
|
+
def test_validates_acceptance_of_generates_message_with_custom_default_message
|
194
|
+
Topic.validates_acceptance_of :title, :message => 'custom', :allow_nil => false
|
195
|
+
@topic.errors.expects(:generate_message).with(:title, :accepted, {:default => 'custom'})
|
196
|
+
@topic.valid?
|
197
|
+
end
|
203
198
|
|
204
|
-
|
199
|
+
# validates_presence_of w/ mocha
|
205
200
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
201
|
+
def test_validates_presence_of_generates_message
|
202
|
+
Topic.validates_presence_of :title
|
203
|
+
@topic.errors.expects(:generate_message).with(:title, :blank, {:default => nil})
|
204
|
+
@topic.valid?
|
205
|
+
end
|
211
206
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
207
|
+
def test_validates_presence_of_generates_message_with_custom_default_message
|
208
|
+
Topic.validates_presence_of :title, :message => 'custom'
|
209
|
+
@topic.errors.expects(:generate_message).with(:title, :blank, {:default => 'custom'})
|
210
|
+
@topic.valid?
|
211
|
+
end
|
217
212
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
213
|
+
def test_validates_length_of_within_generates_message_with_title_too_short
|
214
|
+
Topic.validates_length_of :title, :within => 3..5
|
215
|
+
@topic.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :default => nil})
|
216
|
+
@topic.valid?
|
217
|
+
end
|
223
218
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
219
|
+
def test_validates_length_of_within_generates_message_with_title_too_short_and_custom_default_message
|
220
|
+
Topic.validates_length_of :title, :within => 3..5, :too_short => 'custom'
|
221
|
+
@topic.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :default => 'custom'})
|
222
|
+
@topic.valid?
|
223
|
+
end
|
229
224
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
225
|
+
def test_validates_length_of_within_generates_message_with_title_too_long
|
226
|
+
Topic.validates_length_of :title, :within => 3..5
|
227
|
+
@topic.title = 'this title is too long'
|
228
|
+
@topic.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => nil})
|
229
|
+
@topic.valid?
|
230
|
+
end
|
236
231
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
232
|
+
def test_validates_length_of_within_generates_message_with_title_too_long_and_custom_default_message
|
233
|
+
Topic.validates_length_of :title, :within => 3..5, :too_long => 'custom'
|
234
|
+
@topic.title = 'this title is too long'
|
235
|
+
@topic.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => 'custom'})
|
236
|
+
@topic.valid?
|
237
|
+
end
|
243
238
|
|
244
|
-
|
239
|
+
# validates_length_of :within w/ mocha
|
245
240
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
241
|
+
def test_validates_length_of_within_generates_message_with_title_too_short
|
242
|
+
Topic.validates_length_of :title, :within => 3..5
|
243
|
+
@topic.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :default => nil})
|
244
|
+
@topic.valid?
|
245
|
+
end
|
251
246
|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
247
|
+
def test_validates_length_of_within_generates_message_with_title_too_short_and_custom_default_message
|
248
|
+
Topic.validates_length_of :title, :within => 3..5, :too_short => 'custom'
|
249
|
+
@topic.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :default => 'custom'})
|
250
|
+
@topic.valid?
|
251
|
+
end
|
257
252
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
253
|
+
def test_validates_length_of_within_generates_message_with_title_too_long
|
254
|
+
Topic.validates_length_of :title, :within => 3..5
|
255
|
+
@topic.title = 'this title is too long'
|
256
|
+
@topic.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => nil})
|
257
|
+
@topic.valid?
|
258
|
+
end
|
264
259
|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
260
|
+
def test_validates_length_of_within_generates_message_with_title_too_long_and_custom_default_message
|
261
|
+
Topic.validates_length_of :title, :within => 3..5, :too_long => 'custom'
|
262
|
+
@topic.title = 'this title is too long'
|
263
|
+
@topic.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => 'custom'})
|
264
|
+
@topic.valid?
|
265
|
+
end
|
271
266
|
|
272
|
-
|
267
|
+
# validates_length_of :is w/ mocha
|
273
268
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
269
|
+
def test_validates_length_of_is_generates_message
|
270
|
+
Topic.validates_length_of :title, :is => 5
|
271
|
+
@topic.errors.expects(:generate_message).with(:title, :wrong_length, {:count => 5, :default => nil})
|
272
|
+
@topic.valid?
|
273
|
+
end
|
279
274
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
275
|
+
def test_validates_length_of_is_generates_message_with_custom_default_message
|
276
|
+
Topic.validates_length_of :title, :is => 5, :message => 'custom'
|
277
|
+
@topic.errors.expects(:generate_message).with(:title, :wrong_length, {:count => 5, :default => 'custom'})
|
278
|
+
@topic.valid?
|
279
|
+
end
|
285
280
|
|
286
|
-
|
281
|
+
# validates_uniqueness_of w/ mocha
|
287
282
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
283
|
+
def test_validates_uniqueness_of_generates_message
|
284
|
+
Topic.validates_uniqueness_of :title
|
285
|
+
@topic.title = unique_topic.title
|
286
|
+
@topic.errors.expects(:generate_message).with(:title, :taken, {:default => nil, :value => 'unique!'})
|
287
|
+
@topic.valid?
|
288
|
+
end
|
294
289
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
290
|
+
def test_validates_uniqueness_of_generates_message_with_custom_default_message
|
291
|
+
Topic.validates_uniqueness_of :title, :message => 'custom'
|
292
|
+
@topic.title = unique_topic.title
|
293
|
+
@topic.errors.expects(:generate_message).with(:title, :taken, {:default => 'custom', :value => 'unique!'})
|
294
|
+
@topic.valid?
|
295
|
+
end
|
301
296
|
|
302
|
-
|
297
|
+
# validates_format_of w/ mocha
|
303
298
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
299
|
+
def test_validates_format_of_generates_message
|
300
|
+
Topic.validates_format_of :title, :with => /^[1-9][0-9]*$/
|
301
|
+
@topic.title = '72x'
|
302
|
+
@topic.errors.expects(:generate_message).with(:title, :invalid, {:value => '72x', :default => nil})
|
303
|
+
@topic.valid?
|
304
|
+
end
|
310
305
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
306
|
+
def test_validates_format_of_generates_message_with_custom_default_message
|
307
|
+
Topic.validates_format_of :title, :with => /^[1-9][0-9]*$/, :message => 'custom'
|
308
|
+
@topic.title = '72x'
|
309
|
+
@topic.errors.expects(:generate_message).with(:title, :invalid, {:value => '72x', :default => 'custom'})
|
310
|
+
@topic.valid?
|
311
|
+
end
|
317
312
|
|
318
|
-
|
313
|
+
# validates_inclusion_of w/ mocha
|
319
314
|
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
315
|
+
def test_validates_inclusion_of_generates_message
|
316
|
+
Topic.validates_inclusion_of :title, :in => %w(a b c)
|
317
|
+
@topic.title = 'z'
|
318
|
+
@topic.errors.expects(:generate_message).with(:title, :inclusion, {:value => 'z', :default => nil})
|
319
|
+
@topic.valid?
|
320
|
+
end
|
326
321
|
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
322
|
+
def test_validates_inclusion_of_generates_message_with_custom_default_message
|
323
|
+
Topic.validates_inclusion_of :title, :in => %w(a b c), :message => 'custom'
|
324
|
+
@topic.title = 'z'
|
325
|
+
@topic.errors.expects(:generate_message).with(:title, :inclusion, {:value => 'z', :default => 'custom'})
|
326
|
+
@topic.valid?
|
327
|
+
end
|
333
328
|
|
334
|
-
|
329
|
+
# validates_exclusion_of w/ mocha
|
335
330
|
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
331
|
+
def test_validates_exclusion_of_generates_message
|
332
|
+
Topic.validates_exclusion_of :title, :in => %w(a b c)
|
333
|
+
@topic.title = 'a'
|
334
|
+
@topic.errors.expects(:generate_message).with(:title, :exclusion, {:value => 'a', :default => nil})
|
335
|
+
@topic.valid?
|
336
|
+
end
|
342
337
|
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
338
|
+
def test_validates_exclusion_of_generates_message_with_custom_default_message
|
339
|
+
Topic.validates_exclusion_of :title, :in => %w(a b c), :message => 'custom'
|
340
|
+
@topic.title = 'a'
|
341
|
+
@topic.errors.expects(:generate_message).with(:title, :exclusion, {:value => 'a', :default => 'custom'})
|
342
|
+
@topic.valid?
|
343
|
+
end
|
349
344
|
|
350
|
-
|
345
|
+
# validates_numericality_of without :only_integer w/ mocha
|
351
346
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
347
|
+
def test_validates_numericality_of_generates_message
|
348
|
+
Topic.validates_numericality_of :title
|
349
|
+
@topic.title = 'a'
|
350
|
+
@topic.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => nil})
|
351
|
+
@topic.valid?
|
352
|
+
end
|
358
353
|
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
354
|
+
def test_validates_numericality_of_generates_message_with_custom_default_message
|
355
|
+
Topic.validates_numericality_of :title, :message => 'custom'
|
356
|
+
@topic.title = 'a'
|
357
|
+
@topic.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => 'custom'})
|
358
|
+
@topic.valid?
|
359
|
+
end
|
365
360
|
|
366
|
-
|
361
|
+
# validates_numericality_of with :only_integer w/ mocha
|
367
362
|
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
363
|
+
def test_validates_numericality_of_only_integer_generates_message
|
364
|
+
Topic.validates_numericality_of :title, :only_integer => true
|
365
|
+
@topic.title = 'a'
|
366
|
+
@topic.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => nil})
|
367
|
+
@topic.valid?
|
368
|
+
end
|
374
369
|
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
370
|
+
def test_validates_numericality_of_only_integer_generates_message_with_custom_default_message
|
371
|
+
Topic.validates_numericality_of :title, :only_integer => true, :message => 'custom'
|
372
|
+
@topic.title = 'a'
|
373
|
+
@topic.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => 'custom'})
|
374
|
+
@topic.valid?
|
375
|
+
end
|
381
376
|
|
382
|
-
|
377
|
+
# validates_numericality_of :odd w/ mocha
|
383
378
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
379
|
+
def test_validates_numericality_of_odd_generates_message
|
380
|
+
Topic.validates_numericality_of :title, :only_integer => true, :odd => true
|
381
|
+
@topic.title = 0
|
382
|
+
@topic.errors.expects(:generate_message).with(:title, :odd, {:value => 0, :default => nil})
|
383
|
+
@topic.valid?
|
384
|
+
end
|
390
385
|
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
386
|
+
def test_validates_numericality_of_odd_generates_message_with_custom_default_message
|
387
|
+
Topic.validates_numericality_of :title, :only_integer => true, :odd => true, :message => 'custom'
|
388
|
+
@topic.title = 0
|
389
|
+
@topic.errors.expects(:generate_message).with(:title, :odd, {:value => 0, :default => 'custom'})
|
390
|
+
@topic.valid?
|
391
|
+
end
|
397
392
|
|
398
|
-
|
393
|
+
# validates_numericality_of :less_than w/ mocha
|
399
394
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
395
|
+
def test_validates_numericality_of_less_than_generates_message
|
396
|
+
Topic.validates_numericality_of :title, :only_integer => true, :less_than => 0
|
397
|
+
@topic.title = 1
|
398
|
+
@topic.errors.expects(:generate_message).with(:title, :less_than, {:value => 1, :count => 0, :default => nil})
|
399
|
+
@topic.valid?
|
400
|
+
end
|
406
401
|
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
402
|
+
def test_validates_numericality_of_odd_generates_message_with_custom_default_message
|
403
|
+
Topic.validates_numericality_of :title, :only_integer => true, :less_than => 0, :message => 'custom'
|
404
|
+
@topic.title = 1
|
405
|
+
@topic.errors.expects(:generate_message).with(:title, :less_than, {:value => 1, :count => 0, :default => 'custom'})
|
406
|
+
@topic.valid?
|
407
|
+
end
|
413
408
|
|
414
|
-
|
409
|
+
# validates_associated w/ mocha
|
415
410
|
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
411
|
+
def test_validates_associated_generates_message
|
412
|
+
Topic.validates_associated :replies
|
413
|
+
replied_topic.errors.expects(:generate_message).with(:replies, :invalid, {:value => replied_topic.replies, :default => nil})
|
414
|
+
replied_topic.valid?
|
415
|
+
end
|
421
416
|
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
end
|
417
|
+
def test_validates_associated_generates_message_with_custom_default_message
|
418
|
+
Topic.validates_associated :replies
|
419
|
+
replied_topic.errors.expects(:generate_message).with(:replies, :invalid, {:value => replied_topic.replies, :default => nil})
|
420
|
+
replied_topic.valid?
|
427
421
|
end
|
428
422
|
|
429
423
|
# validates_confirmation_of w/o mocha
|