activerecord 2.3.8 → 2.3.9.pre
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 +1 -4
- data/Rakefile +1 -1
- data/examples/performance.rb +2 -0
- data/lib/active_record/association_preload.rb +12 -2
- data/lib/active_record/associations.rb +1 -1
- data/lib/active_record/associations/association_collection.rb +33 -4
- data/lib/active_record/attribute_methods.rb +0 -4
- data/lib/active_record/autosave_association.rb +2 -2
- data/lib/active_record/base.rb +28 -16
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +6 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +2 -1
- data/lib/active_record/dirty.rb +1 -1
- data/lib/active_record/locale/en.yml +11 -11
- data/lib/active_record/locking/optimistic.rb +1 -0
- data/lib/active_record/migration.rb +1 -1
- data/lib/active_record/named_scope.rb +14 -9
- data/lib/active_record/nested_attributes.rb +11 -8
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/session_store.rb +9 -1
- data/lib/active_record/validations.rb +12 -12
- data/lib/active_record/version.rb +1 -1
- data/test/cases/adapter_test.rb +7 -8
- data/test/cases/associations/eager_load_nested_include_test.rb +7 -7
- data/test/cases/associations/eager_load_nested_polymorphic_include.rb +19 -0
- data/test/cases/associations/eager_test.rb +7 -0
- data/test/cases/associations/has_many_associations_test.rb +68 -3
- data/test/cases/associations_test.rb +29 -0
- data/test/cases/base_test.rb +35 -75
- data/test/cases/connection_test_mysql.rb +1 -0
- data/test/cases/counter_cache_test.rb +84 -0
- data/test/cases/locking_test.rb +2 -1
- data/test/cases/migration_test.rb +4 -0
- data/test/cases/named_scope_test.rb +6 -1
- data/test/cases/nested_attributes_test.rb +49 -14
- data/test/cases/reflection_test.rb +5 -5
- data/test/cases/sp_test_mysql.rb +16 -0
- data/test/cases/transactions_test.rb +22 -1
- data/test/cases/validations_i18n_test.rb +12 -12
- data/test/cases/validations_test.rb +42 -30
- data/test/fixtures/fixture_database.sqlite3 +0 -0
- data/test/fixtures/fixture_database_2.sqlite3 +0 -0
- data/test/fixtures/polymorphic_designs.yml +19 -0
- data/test/fixtures/polymorphic_prices.yml +19 -0
- data/test/fixtures/tees.yml +4 -0
- data/test/fixtures/ties.yml +4 -0
- data/test/models/author.rb +2 -0
- data/test/models/event_author.rb +3 -0
- data/test/models/pirate.rb +2 -2
- data/test/models/polymorphic_design.rb +3 -0
- data/test/models/polymorphic_price.rb +3 -0
- data/test/models/post.rb +2 -0
- data/test/models/tee.rb +4 -0
- data/test/models/tie.rb +4 -0
- data/test/schema/mysql_specific_schema.rb +7 -0
- data/test/schema/schema.rb +16 -0
- metadata +24 -13
- data/examples/performance.sql +0 -85
- data/test/cases/encoding_test.rb +0 -6
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
@@ -48,6 +48,7 @@ class MysqlConnectionTest < ActiveRecord::TestCase
|
|
48
48
|
def test_multi_results
|
49
49
|
rows = ActiveRecord::Base.connection.select_rows('CALL ten();')
|
50
50
|
assert_equal 10, rows[0][0].to_i, "ten() did not return 10 as expected: #{rows.inspect}"
|
51
|
+
assert @connection.active?, "Bad connection use by 'MysqlAdapter.select_rows'"
|
51
52
|
end
|
52
53
|
end
|
53
54
|
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'cases/helper'
|
2
|
+
require 'models/topic'
|
3
|
+
require 'models/reply'
|
4
|
+
require 'models/category'
|
5
|
+
require 'models/categorization'
|
6
|
+
|
7
|
+
class CounterCacheTest < ActiveRecord::TestCase
|
8
|
+
fixtures :topics, :categories, :categorizations
|
9
|
+
|
10
|
+
class SpecialTopic < ::Topic
|
11
|
+
has_many :special_replies, :foreign_key => 'parent_id'
|
12
|
+
end
|
13
|
+
|
14
|
+
class SpecialReply < ::Reply
|
15
|
+
belongs_to :special_topic, :foreign_key => 'parent_id', :counter_cache => 'replies_count'
|
16
|
+
end
|
17
|
+
|
18
|
+
test "increment counter" do
|
19
|
+
topic = Topic.find(1)
|
20
|
+
assert_difference 'topic.reload.replies_count' do
|
21
|
+
Topic.increment_counter(:replies_count, topic.id)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
test "decrement counter" do
|
26
|
+
topic = Topic.find(1)
|
27
|
+
assert_difference 'topic.reload.replies_count', -1 do
|
28
|
+
Topic.decrement_counter(:replies_count, topic.id)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
test "reset counters" do
|
33
|
+
topic = Topic.find(1)
|
34
|
+
# throw the count off by 1
|
35
|
+
Topic.increment_counter(:replies_count, topic.id)
|
36
|
+
|
37
|
+
# check that it gets reset
|
38
|
+
assert_difference 'topic.reload.replies_count', -1 do
|
39
|
+
Topic.reset_counters(topic.id, :replies)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
test "reset counters with string argument" do
|
44
|
+
topic = Topic.find(1)
|
45
|
+
Topic.increment_counter('replies_count', topic.id)
|
46
|
+
|
47
|
+
assert_difference 'topic.reload.replies_count', -1 do
|
48
|
+
Topic.reset_counters(topic.id, 'replies')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
test "reset counters with modularized and camelized classnames" do
|
53
|
+
special = SpecialTopic.create!(:title => 'Special')
|
54
|
+
SpecialTopic.increment_counter(:replies_count, special.id)
|
55
|
+
|
56
|
+
assert_difference 'special.reload.replies_count', -1 do
|
57
|
+
SpecialTopic.reset_counters(special.id, :special_replies)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
test "update counter with initial null value" do
|
62
|
+
category = categories(:general)
|
63
|
+
assert_equal 2, category.categorizations.count
|
64
|
+
assert_nil category.categorizations_count
|
65
|
+
|
66
|
+
Category.update_counters(category.id, :categorizations_count => category.categorizations.count)
|
67
|
+
assert_equal 2, category.reload.categorizations_count
|
68
|
+
end
|
69
|
+
|
70
|
+
test "update counter for decrement" do
|
71
|
+
topic = Topic.find(1)
|
72
|
+
assert_difference 'topic.reload.replies_count', -3 do
|
73
|
+
Topic.update_counters(topic.id, :replies_count => -3)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
test "update counters of multiple records" do
|
78
|
+
t1, t2 = topics(:first, :second)
|
79
|
+
|
80
|
+
assert_difference ['t1.reload.replies_count', 't2.reload.replies_count'], 2 do
|
81
|
+
Topic.update_counters([t1.id, t2.id], :replies_count => 2)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/test/cases/locking_test.rb
CHANGED
@@ -53,7 +53,8 @@ class OptimisticLockingTest < ActiveRecord::TestCase
|
|
53
53
|
assert_raises(ActiveRecord::StaleObjectError) { p2.destroy }
|
54
54
|
|
55
55
|
assert p1.destroy
|
56
|
-
|
56
|
+
assert p1.frozen?
|
57
|
+
assert p1.destroyed?
|
57
58
|
assert_raises(ActiveRecord::RecordNotFound) { Person.find(1) }
|
58
59
|
end
|
59
60
|
|
@@ -739,6 +739,10 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
739
739
|
ActiveRecord::Base.connection.drop_table(:hats)
|
740
740
|
end
|
741
741
|
|
742
|
+
def test_remove_column_no_second_parameter_raises_exception
|
743
|
+
assert_raise(ArgumentError) { Person.connection.remove_column("funny") }
|
744
|
+
end
|
745
|
+
|
742
746
|
def test_change_type_of_not_null_column
|
743
747
|
assert_nothing_raised do
|
744
748
|
Topic.connection.change_column "topics", "written_on", :datetime, :null => false
|
@@ -9,6 +9,11 @@ require 'models/developer'
|
|
9
9
|
class NamedScopeTest < ActiveRecord::TestCase
|
10
10
|
fixtures :posts, :authors, :topics, :comments, :author_addresses
|
11
11
|
|
12
|
+
def test_named_scope_with_STI
|
13
|
+
assert_equal 5,Post.with_type_self.count
|
14
|
+
assert_equal 1,SpecialPost.with_type_self.count
|
15
|
+
end
|
16
|
+
|
12
17
|
def test_implements_enumerable
|
13
18
|
assert !Topic.find(:all).empty?
|
14
19
|
|
@@ -265,7 +270,7 @@ class NamedScopeTest < ActiveRecord::TestCase
|
|
265
270
|
end
|
266
271
|
|
267
272
|
def test_rand_should_select_a_random_object_from_proxy
|
268
|
-
assert Topic.approved.
|
273
|
+
assert Topic.approved.sample.is_a?(Topic)
|
269
274
|
end
|
270
275
|
|
271
276
|
def test_should_use_where_in_query_for_named_scope
|
@@ -175,12 +175,6 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
|
|
175
175
|
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
|
176
176
|
end
|
177
177
|
|
178
|
-
def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
|
179
|
-
assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find Ship with ID=1234567890 for Pirate with ID=#{@pirate.id}" do
|
180
|
-
@pirate.ship_attributes = { :id => 1234567890 }
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
178
|
def test_should_take_a_hash_with_string_keys_and_update_the_associated_model
|
185
179
|
@pirate.reload.ship_attributes = { 'id' => @ship.id, 'name' => 'Davy Jones Gold Dagger' }
|
186
180
|
|
@@ -330,10 +324,13 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
|
|
330
324
|
assert_equal 'Arr', @ship.pirate.catchphrase
|
331
325
|
end
|
332
326
|
|
333
|
-
def
|
334
|
-
|
335
|
-
|
336
|
-
|
327
|
+
def test_should_associate_with_record_if_parent_record_is_not_saved
|
328
|
+
@ship.destroy
|
329
|
+
@pirate = Pirate.create(:catchphrase => 'Arr')
|
330
|
+
@ship = Ship.new(:name => 'Nights Dirty Lightning', :pirate_attributes => { :id => @pirate.id, :catchphrase => @pirate.catchphrase})
|
331
|
+
|
332
|
+
assert_equal @ship.name, 'Nights Dirty Lightning'
|
333
|
+
assert_equal @pirate, @ship.pirate
|
337
334
|
end
|
338
335
|
|
339
336
|
def test_should_take_a_hash_with_string_keys_and_update_the_associated_model
|
@@ -437,6 +434,11 @@ module NestedAttributesOnACollectionAssociationTests
|
|
437
434
|
assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.reload.name, @child_2.reload.name]
|
438
435
|
end
|
439
436
|
|
437
|
+
def test_should_assign_existing_children_if_parent_is_new
|
438
|
+
@pirate = Pirate.new({:catchphrase => "Don' botharr talkin' like one, savvy?"}.merge(@alternate_params))
|
439
|
+
assert_equal ['Grace OMalley', 'Privateers Greed'], [@pirate.send(@association_name)[0].name, @pirate.send(@association_name)[1].name]
|
440
|
+
end
|
441
|
+
|
440
442
|
def test_should_take_an_array_and_assign_the_attributes_to_the_associated_models
|
441
443
|
@pirate.send(association_setter, @alternate_params[association_getter].values)
|
442
444
|
@pirate.save
|
@@ -465,6 +467,33 @@ module NestedAttributesOnACollectionAssociationTests
|
|
465
467
|
assert_equal 'Grace OMalley', @child_1.reload.name
|
466
468
|
end
|
467
469
|
|
470
|
+
def test_should_not_overwrite_unsaved_updates_when_loading_association
|
471
|
+
@pirate.reload
|
472
|
+
@pirate.send(association_setter, [{ :id => @child_1.id, :name => 'Grace OMalley' }])
|
473
|
+
assert_equal 'Grace OMalley', @pirate.send(@association_name).send(:load_target).find { |r| r.id == @child_1.id }.name
|
474
|
+
end
|
475
|
+
|
476
|
+
def test_should_preserve_order_when_not_overwriting_unsaved_updates
|
477
|
+
@pirate.reload
|
478
|
+
@pirate.send(association_setter, [{ :id => @child_1.id, :name => 'Grace OMalley' }])
|
479
|
+
assert_equal @child_1.id, @pirate.send(@association_name).send(:load_target).first.id
|
480
|
+
end
|
481
|
+
|
482
|
+
def test_should_refresh_saved_records_when_not_overwriting_unsaved_updates
|
483
|
+
@pirate.reload
|
484
|
+
record = @pirate.class.reflect_on_association(@association_name).klass.new(:name => 'Grace OMalley')
|
485
|
+
@pirate.send(@association_name) << record
|
486
|
+
record.save!
|
487
|
+
@pirate.send(@association_name).last.update_attributes!(:name => 'Polly')
|
488
|
+
assert_equal 'Polly', @pirate.send(@association_name).send(:load_target).last.name
|
489
|
+
end
|
490
|
+
|
491
|
+
def test_should_not_remove_scheduled_destroys_when_loading_association
|
492
|
+
@pirate.reload
|
493
|
+
@pirate.send(association_setter, [{ :id => @child_1.id, :_destroy => '1' }])
|
494
|
+
assert @pirate.send(@association_name).send(:load_target).find { |r| r.id == @child_1.id }.marked_for_destruction?
|
495
|
+
end
|
496
|
+
|
468
497
|
def test_should_take_a_hash_with_composite_id_keys_and_assign_the_attributes_to_the_associated_models
|
469
498
|
@child_1.stubs(:id).returns('ABC1X')
|
470
499
|
@child_2.stubs(:id).returns('ABC2X')
|
@@ -479,8 +508,8 @@ module NestedAttributesOnACollectionAssociationTests
|
|
479
508
|
assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.name, @child_2.name]
|
480
509
|
end
|
481
510
|
|
482
|
-
def
|
483
|
-
|
511
|
+
def test_should_not_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
|
512
|
+
assert_nothing_raised ActiveRecord::RecordNotFound do
|
484
513
|
@pirate.attributes = { association_getter => [{ :id => 1234567890 }] }
|
485
514
|
end
|
486
515
|
end
|
@@ -781,7 +810,13 @@ class TestHasManyAutosaveAssoictaionWhichItselfHasAutosaveAssociations < ActiveR
|
|
781
810
|
@part = @ship.parts.create!(:name => "Mast")
|
782
811
|
@trinket = @part.trinkets.create!(:name => "Necklace")
|
783
812
|
end
|
784
|
-
|
813
|
+
|
814
|
+
test "if association is not loaded and association record is saved and then in memory record attributes should be saved" do
|
815
|
+
@ship.parts_attributes=[{:id => @part.id,:name =>'Deck'}]
|
816
|
+
assert_equal 1, @ship.parts.proxy_target.size
|
817
|
+
assert_equal 'Deck', @ship.parts[0].name
|
818
|
+
end
|
819
|
+
|
785
820
|
test "when grandchild changed in memory, saving parent should save grandchild" do
|
786
821
|
@trinket.name = "changed"
|
787
822
|
@ship.save
|
@@ -810,4 +845,4 @@ class TestHasManyAutosaveAssoictaionWhichItselfHasAutosaveAssociations < ActiveR
|
|
810
845
|
ShipPart.create!(:ship => @ship, :name => "Stern")
|
811
846
|
assert_no_queries { @ship.valid? }
|
812
847
|
end
|
813
|
-
end
|
848
|
+
end
|
@@ -24,25 +24,25 @@ class ReflectionTest < ActiveRecord::TestCase
|
|
24
24
|
|
25
25
|
def test_read_attribute_names
|
26
26
|
assert_equal(
|
27
|
-
%w( id title author_name author_email_address bonus_time written_on last_read content approved replies_count parent_id parent_title type ).sort,
|
27
|
+
%w( id title author_name author_email_address bonus_time written_on last_read content group approved replies_count parent_id parent_title type ).sort,
|
28
28
|
@first.attribute_names
|
29
29
|
)
|
30
30
|
end
|
31
31
|
|
32
32
|
def test_columns
|
33
|
-
assert_equal
|
33
|
+
assert_equal 14, Topic.columns.length
|
34
34
|
end
|
35
35
|
|
36
36
|
def test_columns_are_returned_in_the_order_they_were_declared
|
37
37
|
column_names = Topic.columns.map { |column| column.name }
|
38
|
-
assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content approved replies_count parent_id parent_title type), column_names
|
38
|
+
assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content approved replies_count parent_id parent_title type group), column_names
|
39
39
|
end
|
40
40
|
|
41
41
|
def test_content_columns
|
42
42
|
content_columns = Topic.content_columns
|
43
43
|
content_column_names = content_columns.map {|column| column.name}
|
44
|
-
assert_equal
|
45
|
-
assert_equal %w(title author_name author_email_address written_on bonus_time last_read content approved parent_title).sort, content_column_names.sort
|
44
|
+
assert_equal 10, content_columns.length
|
45
|
+
assert_equal %w(title author_name author_email_address written_on bonus_time last_read content group approved parent_title).sort, content_column_names.sort
|
46
46
|
end
|
47
47
|
|
48
48
|
def test_column_string_type_and_limit
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "cases/helper"
|
2
|
+
require 'models/topic'
|
3
|
+
require 'models/minimalistic'
|
4
|
+
|
5
|
+
class StoredProcedureTest < ActiveRecord::TestCase
|
6
|
+
fixtures :topics
|
7
|
+
|
8
|
+
# Test that MySQL allows multiple results for stored procedures
|
9
|
+
if Mysql.const_defined?(:CLIENT_MULTI_RESULTS)
|
10
|
+
def test_multi_results_from_find_by_sql
|
11
|
+
topics = Topic.find_by_sql 'CALL topics();'
|
12
|
+
assert_equal 1, topics.size
|
13
|
+
assert ActiveRecord::Base.connection.active?, "Bad connection use by 'MysqlAdapter.select'"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -3,10 +3,12 @@ require 'models/topic'
|
|
3
3
|
require 'models/reply'
|
4
4
|
require 'models/developer'
|
5
5
|
require 'models/book'
|
6
|
+
require 'models/author'
|
7
|
+
require 'models/post'
|
6
8
|
|
7
9
|
class TransactionTest < ActiveRecord::TestCase
|
8
10
|
self.use_transactional_fixtures = false
|
9
|
-
fixtures :topics, :developers
|
11
|
+
fixtures :topics, :developers, :authors, :posts
|
10
12
|
|
11
13
|
def setup
|
12
14
|
@first, @second = Topic.find(1, 2).sort_by { |t| t.id }
|
@@ -34,6 +36,25 @@ class TransactionTest < ActiveRecord::TestCase
|
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
39
|
+
def test_update_attributes_should_rollback_on_failure
|
40
|
+
author = Author.find(1)
|
41
|
+
posts_count = author.posts.size
|
42
|
+
assert posts_count > 0
|
43
|
+
status = author.update_attributes(:name => nil, :post_ids => [])
|
44
|
+
assert !status
|
45
|
+
assert_equal posts_count, author.posts(true).size
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_update_attributes_should_rollback_on_failure!
|
49
|
+
author = Author.find(1)
|
50
|
+
posts_count = author.posts.size
|
51
|
+
assert posts_count > 0
|
52
|
+
assert_raise(ActiveRecord::RecordInvalid) do
|
53
|
+
author.update_attributes!(:name => nil, :post_ids => [])
|
54
|
+
end
|
55
|
+
assert_equal posts_count, author.posts(true).size
|
56
|
+
end
|
57
|
+
|
37
58
|
def test_successful_with_return
|
38
59
|
class << Topic.connection
|
39
60
|
alias :real_commit_db_transaction :commit_db_transaction
|
@@ -486,20 +486,20 @@ class ActiveRecordErrorI18nTests < ActiveSupport::TestCase
|
|
486
486
|
end
|
487
487
|
|
488
488
|
test ":default is only given to message if a symbol is supplied" do
|
489
|
-
store_translations(:errors => { :messages => { :"foo bar" => "You fooed: {
|
489
|
+
store_translations(:errors => { :messages => { :"foo bar" => "You fooed: %{value}." } })
|
490
490
|
@reply.errors.add(:title, :inexistent, :default => "foo bar")
|
491
491
|
assert_equal "foo bar", @reply.errors[:title]
|
492
492
|
end
|
493
493
|
|
494
494
|
test "#generate_message passes the model attribute value for interpolation" do
|
495
|
-
store_translations(:errors => { :messages => { :foo => "You fooed: {
|
495
|
+
store_translations(:errors => { :messages => { :foo => "You fooed: %{value}." } })
|
496
496
|
@reply.title = "da title"
|
497
497
|
assert_error_message 'You fooed: da title.', :title, :foo
|
498
498
|
end
|
499
499
|
|
500
500
|
test "#generate_message passes the human_name of the model for interpolation" do
|
501
501
|
store_translations(
|
502
|
-
:errors => { :messages => { :foo => "You fooed: {
|
502
|
+
:errors => { :messages => { :foo => "You fooed: %{model}." } },
|
503
503
|
:models => { :topic => 'da topic' }
|
504
504
|
)
|
505
505
|
assert_error_message 'You fooed: da topic.', :title, :foo
|
@@ -507,7 +507,7 @@ class ActiveRecordErrorI18nTests < ActiveSupport::TestCase
|
|
507
507
|
|
508
508
|
test "#generate_message passes the human_name of the attribute for interpolation" do
|
509
509
|
store_translations(
|
510
|
-
:errors => { :messages => { :foo => "You fooed: {
|
510
|
+
:errors => { :messages => { :foo => "You fooed: %{attribute}." } },
|
511
511
|
:attributes => { :topic => { :title => 'da topic title' } }
|
512
512
|
)
|
513
513
|
assert_error_message 'You fooed: da topic title.', :title, :foo
|
@@ -607,17 +607,17 @@ class ActiveRecordErrorI18nTests < ActiveSupport::TestCase
|
|
607
607
|
end
|
608
608
|
|
609
609
|
test "#full_message with a format present" do
|
610
|
-
store_translations(:errors => { :messages => { :kaputt => 'is kaputt' }, :full_messages => { :format => '{
|
610
|
+
store_translations(:errors => { :messages => { :kaputt => 'is kaputt' }, :full_messages => { :format => '%{attribute}: %{message}' } })
|
611
611
|
assert_full_message 'Title: is kaputt', :title, :kaputt
|
612
612
|
end
|
613
613
|
|
614
614
|
test "#full_message with a type specific format present" do
|
615
|
-
store_translations(:errors => { :messages => { :kaputt => 'is kaputt' }, :full_messages => { :kaputt => '{
|
615
|
+
store_translations(:errors => { :messages => { :kaputt => 'is kaputt' }, :full_messages => { :kaputt => '%{attribute} %{message}!' } })
|
616
616
|
assert_full_message 'Title is kaputt!', :title, :kaputt
|
617
617
|
end
|
618
618
|
|
619
619
|
test "#full_message with class-level specified custom message" do
|
620
|
-
store_translations(:errors => { :messages => { :broken => 'is kaputt' }, :full_messages => { :broken => '{
|
620
|
+
store_translations(:errors => { :messages => { :broken => 'is kaputt' }, :full_messages => { :broken => '%{attribute} %{message}?!' } })
|
621
621
|
assert_full_message 'Title is kaputt?!', :title, :kaputt, :message => :broken
|
622
622
|
end
|
623
623
|
|
@@ -625,7 +625,7 @@ class ActiveRecordErrorI18nTests < ActiveSupport::TestCase
|
|
625
625
|
store_translations(:my_errors => { :messages => { :kaputt => 'is kaputt' } })
|
626
626
|
assert_full_message 'Title is kaputt', :title, :kaputt, :scope => [:activerecord, :my_errors]
|
627
627
|
|
628
|
-
store_translations(:my_errors => { :full_messages => { :kaputt => '{
|
628
|
+
store_translations(:my_errors => { :full_messages => { :kaputt => '%{attribute} %{message}!' } })
|
629
629
|
assert_full_message 'Title is kaputt!', :title, :kaputt, :scope => [:activerecord, :my_errors]
|
630
630
|
end
|
631
631
|
|
@@ -763,7 +763,7 @@ class ActiveRecordDefaultErrorMessagesI18nTests < ActiveSupport::TestCase
|
|
763
763
|
end
|
764
764
|
|
765
765
|
test "custom message string interpolation" do
|
766
|
-
assert_equal 'custom message title', error_message(:invalid, :default => 'custom message {
|
766
|
+
assert_equal 'custom message title', error_message(:invalid, :default => 'custom message %{value}', :value => 'title')
|
767
767
|
end
|
768
768
|
end
|
769
769
|
|
@@ -897,14 +897,14 @@ class ActiveRecordValidationsI18nFullMessagesFullStackTests < ActiveSupport::Tes
|
|
897
897
|
|
898
898
|
test "full_message format stored per custom error message key" do
|
899
899
|
assert_full_message("Name is broken!") do
|
900
|
-
store_translations :errors => { :messages => { :broken => 'is broken' }, :full_messages => { :broken => '{
|
900
|
+
store_translations :errors => { :messages => { :broken => 'is broken' }, :full_messages => { :broken => '%{attribute} %{message}!' } }
|
901
901
|
I18nPerson.validates_presence_of :name, :message => :broken
|
902
902
|
end
|
903
903
|
end
|
904
904
|
|
905
905
|
test "full_message format stored per error type" do
|
906
906
|
assert_full_message("Name can't be blank!") do
|
907
|
-
store_translations :errors => { :full_messages => { :blank => '{
|
907
|
+
store_translations :errors => { :full_messages => { :blank => '%{attribute} %{message}!' } }
|
908
908
|
I18nPerson.validates_presence_of :name
|
909
909
|
end
|
910
910
|
end
|
@@ -912,7 +912,7 @@ class ActiveRecordValidationsI18nFullMessagesFullStackTests < ActiveSupport::Tes
|
|
912
912
|
|
913
913
|
test "full_message format stored as default" do
|
914
914
|
assert_full_message("Name: can't be blank") do
|
915
|
-
store_translations :errors => { :full_messages => { :format => '{
|
915
|
+
store_translations :errors => { :full_messages => { :format => '%{attribute}: %{message}' } }
|
916
916
|
I18nPerson.validates_presence_of :name
|
917
917
|
end
|
918
918
|
end
|
@@ -434,6 +434,18 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
434
434
|
end
|
435
435
|
end
|
436
436
|
|
437
|
+
def test_validate_uniqueness_with_reserved_word_as_scope
|
438
|
+
repair_validations(Reply) do
|
439
|
+
Topic.validates_uniqueness_of(:content, :scope => "group")
|
440
|
+
|
441
|
+
t1 = Topic.create "title" => "t1", "content" => "hello world2"
|
442
|
+
assert t1.valid?
|
443
|
+
|
444
|
+
t2 = Topic.create "title" => "t2", "content" => "hello world2"
|
445
|
+
assert !t2.valid?
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
437
449
|
def test_validate_uniqueness_scoped_to_defining_class
|
438
450
|
t = Topic.create("title" => "What, me worry?")
|
439
451
|
|
@@ -678,7 +690,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
678
690
|
end
|
679
691
|
|
680
692
|
def test_validate_format_with_formatted_message
|
681
|
-
Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be {
|
693
|
+
Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be %{value}")
|
682
694
|
t = Topic.create(:title => 'Invalid title')
|
683
695
|
assert_equal "can't be Invalid title", t.errors.on(:title)
|
684
696
|
end
|
@@ -741,7 +753,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
741
753
|
end
|
742
754
|
|
743
755
|
def test_validates_inclusion_of_with_formatted_message
|
744
|
-
Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option {
|
756
|
+
Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option %{value} is not in the list" )
|
745
757
|
|
746
758
|
assert Topic.create("title" => "a", "content" => "abc").valid?
|
747
759
|
|
@@ -768,7 +780,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
768
780
|
end
|
769
781
|
|
770
782
|
def test_validates_exclusion_of_with_formatted_message
|
771
|
-
Topic.validates_exclusion_of( :title, :in => %w( abe monkey ), :message => "option {
|
783
|
+
Topic.validates_exclusion_of( :title, :in => %w( abe monkey ), :message => "option %{value} is restricted" )
|
772
784
|
|
773
785
|
assert Topic.create("title" => "something", "content" => "abc")
|
774
786
|
|
@@ -868,7 +880,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
868
880
|
end
|
869
881
|
|
870
882
|
def test_optionally_validates_length_of_using_within_on_create
|
871
|
-
Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "my string is too long: {
|
883
|
+
Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "my string is too long: %{count}"
|
872
884
|
|
873
885
|
t = Topic.create("title" => "thisisnotvalid", "content" => "whatever")
|
874
886
|
assert !t.save
|
@@ -889,7 +901,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
889
901
|
end
|
890
902
|
|
891
903
|
def test_optionally_validates_length_of_using_within_on_update
|
892
|
-
Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "my string is too short: {
|
904
|
+
Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "my string is too short: %{count}"
|
893
905
|
|
894
906
|
t = Topic.create("title" => "vali", "content" => "whatever")
|
895
907
|
assert !t.save
|
@@ -953,7 +965,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
953
965
|
def test_validates_length_with_globally_modified_error_message
|
954
966
|
defaults = ActiveSupport::Deprecation.silence { ActiveRecord::Errors.default_error_messages }
|
955
967
|
original_message = defaults[:too_short]
|
956
|
-
defaults[:too_short] = 'tu est trops petit hombre {
|
968
|
+
defaults[:too_short] = 'tu est trops petit hombre %{count}'
|
957
969
|
|
958
970
|
Topic.validates_length_of :title, :minimum => 10
|
959
971
|
t = Topic.create(:title => 'too short')
|
@@ -1004,7 +1016,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1004
1016
|
end
|
1005
1017
|
|
1006
1018
|
def test_validates_length_of_custom_errors_for_minimum_with_message
|
1007
|
-
Topic.validates_length_of( :title, :minimum=>5, :message=>"boo {
|
1019
|
+
Topic.validates_length_of( :title, :minimum=>5, :message=>"boo %{count}" )
|
1008
1020
|
t = Topic.create("title" => "uhoh", "content" => "whatever")
|
1009
1021
|
assert !t.valid?
|
1010
1022
|
assert t.errors.on(:title)
|
@@ -1012,7 +1024,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1012
1024
|
end
|
1013
1025
|
|
1014
1026
|
def test_validates_length_of_custom_errors_for_minimum_with_too_short
|
1015
|
-
Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo {
|
1027
|
+
Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo %{count}" )
|
1016
1028
|
t = Topic.create("title" => "uhoh", "content" => "whatever")
|
1017
1029
|
assert !t.valid?
|
1018
1030
|
assert t.errors.on(:title)
|
@@ -1020,7 +1032,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1020
1032
|
end
|
1021
1033
|
|
1022
1034
|
def test_validates_length_of_custom_errors_for_maximum_with_message
|
1023
|
-
Topic.validates_length_of( :title, :maximum=>5, :message=>"boo {
|
1035
|
+
Topic.validates_length_of( :title, :maximum=>5, :message=>"boo %{count}" )
|
1024
1036
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1025
1037
|
assert !t.valid?
|
1026
1038
|
assert t.errors.on(:title)
|
@@ -1028,7 +1040,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1028
1040
|
end
|
1029
1041
|
|
1030
1042
|
def test_validates_length_of_custom_errors_for_in
|
1031
|
-
Topic.validates_length_of(:title, :in => 10..20, :message => "hoo {
|
1043
|
+
Topic.validates_length_of(:title, :in => 10..20, :message => "hoo %{count}")
|
1032
1044
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1033
1045
|
assert !t.valid?
|
1034
1046
|
assert t.errors.on(:title)
|
@@ -1041,7 +1053,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1041
1053
|
end
|
1042
1054
|
|
1043
1055
|
def test_validates_length_of_custom_errors_for_maximum_with_too_long
|
1044
|
-
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {
|
1056
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}" )
|
1045
1057
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1046
1058
|
assert !t.valid?
|
1047
1059
|
assert t.errors.on(:title)
|
@@ -1049,7 +1061,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1049
1061
|
end
|
1050
1062
|
|
1051
1063
|
def test_validates_length_of_custom_errors_for_is_with_message
|
1052
|
-
Topic.validates_length_of( :title, :is=>5, :message=>"boo {
|
1064
|
+
Topic.validates_length_of( :title, :is=>5, :message=>"boo %{count}" )
|
1053
1065
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1054
1066
|
assert !t.valid?
|
1055
1067
|
assert t.errors.on(:title)
|
@@ -1057,7 +1069,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1057
1069
|
end
|
1058
1070
|
|
1059
1071
|
def test_validates_length_of_custom_errors_for_is_with_wrong_length
|
1060
|
-
Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo {
|
1072
|
+
Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo %{count}" )
|
1061
1073
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1062
1074
|
assert !t.valid?
|
1063
1075
|
assert t.errors.on(:title)
|
@@ -1123,7 +1135,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1123
1135
|
|
1124
1136
|
def test_optionally_validates_length_of_using_within_on_create_utf8
|
1125
1137
|
with_kcode('UTF8') do
|
1126
|
-
Topic.validates_length_of :title, :within => 5..10, :on => :create, :too_long => "長すぎます: {
|
1138
|
+
Topic.validates_length_of :title, :within => 5..10, :on => :create, :too_long => "長すぎます: %{count}"
|
1127
1139
|
|
1128
1140
|
t = Topic.create("title" => "一二三四五六七八九十A", "content" => "whatever")
|
1129
1141
|
assert !t.save
|
@@ -1146,7 +1158,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1146
1158
|
|
1147
1159
|
def test_optionally_validates_length_of_using_within_on_update_utf8
|
1148
1160
|
with_kcode('UTF8') do
|
1149
|
-
Topic.validates_length_of :title, :within => 5..10, :on => :update, :too_short => "短すぎます: {
|
1161
|
+
Topic.validates_length_of :title, :within => 5..10, :on => :update, :too_short => "短すぎます: %{count}"
|
1150
1162
|
|
1151
1163
|
t = Topic.create("title" => "一二三4", "content" => "whatever")
|
1152
1164
|
assert !t.save
|
@@ -1181,7 +1193,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1181
1193
|
end
|
1182
1194
|
|
1183
1195
|
def test_validates_length_of_with_block
|
1184
|
-
Topic.validates_length_of :content, :minimum => 5, :too_short=>"Your essay must be at least {
|
1196
|
+
Topic.validates_length_of :content, :minimum => 5, :too_short=>"Your essay must be at least %{count} words.",
|
1185
1197
|
:tokenizer => lambda {|str| str.scan(/\w+/) }
|
1186
1198
|
t = Topic.create!(:content => "this content should be long enough")
|
1187
1199
|
assert t.valid?
|
@@ -1356,7 +1368,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1356
1368
|
|
1357
1369
|
def test_if_validation_using_method_true
|
1358
1370
|
# When the method returns true
|
1359
|
-
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {
|
1371
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => :condition_is_true )
|
1360
1372
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1361
1373
|
assert !t.valid?
|
1362
1374
|
assert t.errors.on(:title)
|
@@ -1365,7 +1377,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1365
1377
|
|
1366
1378
|
def test_unless_validation_using_method_true
|
1367
1379
|
# When the method returns true
|
1368
|
-
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {
|
1380
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => :condition_is_true )
|
1369
1381
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1370
1382
|
assert t.valid?
|
1371
1383
|
assert !t.errors.on(:title)
|
@@ -1373,7 +1385,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1373
1385
|
|
1374
1386
|
def test_if_validation_using_method_false
|
1375
1387
|
# When the method returns false
|
1376
|
-
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {
|
1388
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => :condition_is_true_but_its_not )
|
1377
1389
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1378
1390
|
assert t.valid?
|
1379
1391
|
assert !t.errors.on(:title)
|
@@ -1381,7 +1393,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1381
1393
|
|
1382
1394
|
def test_unless_validation_using_method_false
|
1383
1395
|
# When the method returns false
|
1384
|
-
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {
|
1396
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => :condition_is_true_but_its_not )
|
1385
1397
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1386
1398
|
assert !t.valid?
|
1387
1399
|
assert t.errors.on(:title)
|
@@ -1390,7 +1402,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1390
1402
|
|
1391
1403
|
def test_if_validation_using_string_true
|
1392
1404
|
# When the evaluated string returns true
|
1393
|
-
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {
|
1405
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => "a = 1; a == 1" )
|
1394
1406
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1395
1407
|
assert !t.valid?
|
1396
1408
|
assert t.errors.on(:title)
|
@@ -1399,7 +1411,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1399
1411
|
|
1400
1412
|
def test_unless_validation_using_string_true
|
1401
1413
|
# When the evaluated string returns true
|
1402
|
-
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {
|
1414
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => "a = 1; a == 1" )
|
1403
1415
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1404
1416
|
assert t.valid?
|
1405
1417
|
assert !t.errors.on(:title)
|
@@ -1407,7 +1419,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1407
1419
|
|
1408
1420
|
def test_if_validation_using_string_false
|
1409
1421
|
# When the evaluated string returns false
|
1410
|
-
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {
|
1422
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => "false")
|
1411
1423
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1412
1424
|
assert t.valid?
|
1413
1425
|
assert !t.errors.on(:title)
|
@@ -1415,7 +1427,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1415
1427
|
|
1416
1428
|
def test_unless_validation_using_string_false
|
1417
1429
|
# When the evaluated string returns false
|
1418
|
-
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {
|
1430
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => "false")
|
1419
1431
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1420
1432
|
assert !t.valid?
|
1421
1433
|
assert t.errors.on(:title)
|
@@ -1424,7 +1436,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1424
1436
|
|
1425
1437
|
def test_if_validation_using_block_true
|
1426
1438
|
# When the block returns true
|
1427
|
-
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {
|
1439
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
|
1428
1440
|
:if => Proc.new { |r| r.content.size > 4 } )
|
1429
1441
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1430
1442
|
assert !t.valid?
|
@@ -1434,7 +1446,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1434
1446
|
|
1435
1447
|
def test_unless_validation_using_block_true
|
1436
1448
|
# When the block returns true
|
1437
|
-
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {
|
1449
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
|
1438
1450
|
:unless => Proc.new { |r| r.content.size > 4 } )
|
1439
1451
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1440
1452
|
assert t.valid?
|
@@ -1443,7 +1455,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1443
1455
|
|
1444
1456
|
def test_if_validation_using_block_false
|
1445
1457
|
# When the block returns false
|
1446
|
-
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {
|
1458
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
|
1447
1459
|
:if => Proc.new { |r| r.title != "uhohuhoh"} )
|
1448
1460
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1449
1461
|
assert t.valid?
|
@@ -1452,7 +1464,7 @@ class ValidationsTest < ActiveRecord::TestCase
|
|
1452
1464
|
|
1453
1465
|
def test_unless_validation_using_block_false
|
1454
1466
|
# When the block returns false
|
1455
|
-
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {
|
1467
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
|
1456
1468
|
:unless => Proc.new { |r| r.title != "uhohuhoh"} )
|
1457
1469
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1458
1470
|
assert !t.valid?
|
@@ -1634,13 +1646,13 @@ class ValidatesNumericalityTest < ActiveRecord::TestCase
|
|
1634
1646
|
end
|
1635
1647
|
|
1636
1648
|
def test_validates_numericality_with_numeric_message
|
1637
|
-
Topic.validates_numericality_of :approved, :less_than => 4, :message => "smaller than {
|
1649
|
+
Topic.validates_numericality_of :approved, :less_than => 4, :message => "smaller than %{count}"
|
1638
1650
|
topic = Topic.new("title" => "numeric test", "approved" => 10)
|
1639
1651
|
|
1640
1652
|
assert !topic.valid?
|
1641
1653
|
assert_equal "smaller than 4", topic.errors.on(:approved)
|
1642
1654
|
|
1643
|
-
Topic.validates_numericality_of :approved, :greater_than => 4, :message => "greater than {
|
1655
|
+
Topic.validates_numericality_of :approved, :greater_than => 4, :message => "greater than %{count}"
|
1644
1656
|
topic = Topic.new("title" => "numeric test", "approved" => 1)
|
1645
1657
|
|
1646
1658
|
assert !topic.valid?
|