activerecord 2.1.2 → 2.2.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 +32 -6
- data/README +0 -0
- data/Rakefile +4 -5
- data/lib/active_record.rb +11 -10
- data/lib/active_record/aggregations.rb +110 -38
- data/lib/active_record/association_preload.rb +104 -15
- data/lib/active_record/associations.rb +427 -212
- data/lib/active_record/associations/association_collection.rb +101 -16
- data/lib/active_record/associations/association_proxy.rb +65 -13
- data/lib/active_record/associations/belongs_to_association.rb +2 -2
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +13 -3
- data/lib/active_record/associations/has_many_association.rb +28 -28
- data/lib/active_record/associations/has_many_through_association.rb +21 -19
- data/lib/active_record/associations/has_one_association.rb +24 -7
- data/lib/active_record/associations/has_one_through_association.rb +3 -4
- data/lib/active_record/attribute_methods.rb +13 -5
- data/lib/active_record/base.rb +435 -212
- data/lib/active_record/calculations.rb +12 -5
- data/lib/active_record/callbacks.rb +28 -9
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +355 -0
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +42 -215
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +30 -5
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +48 -7
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +10 -4
- data/lib/active_record/connection_adapters/abstract_adapter.rb +67 -26
- data/lib/active_record/connection_adapters/mysql_adapter.rb +71 -45
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +155 -84
- data/lib/active_record/dirty.rb +25 -7
- data/lib/active_record/dynamic_finder_match.rb +41 -0
- data/lib/active_record/fixtures.rb +10 -9
- data/lib/active_record/i18n_interpolation_deprecation.rb +26 -0
- data/lib/active_record/locale/en.yml +54 -0
- data/lib/active_record/migration.rb +47 -10
- data/lib/active_record/named_scope.rb +29 -16
- data/lib/active_record/reflection.rb +118 -54
- data/lib/active_record/schema_dumper.rb +13 -7
- data/lib/active_record/test_case.rb +18 -5
- data/lib/active_record/transactions.rb +89 -34
- data/lib/active_record/validations.rb +270 -180
- data/lib/active_record/version.rb +1 -1
- data/test/cases/active_schema_test_mysql.rb +5 -0
- data/test/cases/adapter_test.rb +6 -0
- data/test/cases/aggregations_test.rb +39 -0
- data/test/cases/associations/belongs_to_associations_test.rb +10 -0
- data/test/cases/associations/eager_load_nested_include_test.rb +30 -12
- data/test/cases/associations/eager_test.rb +54 -5
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +77 -10
- data/test/cases/associations/has_many_associations_test.rb +74 -7
- data/test/cases/associations/has_many_through_associations_test.rb +50 -3
- data/test/cases/associations/has_one_associations_test.rb +17 -0
- data/test/cases/associations/has_one_through_associations_test.rb +49 -1
- data/test/cases/associations_test.rb +0 -0
- data/test/cases/attribute_methods_test.rb +59 -4
- data/test/cases/base_test.rb +93 -21
- data/test/cases/binary_test.rb +1 -5
- data/test/cases/calculations_test.rb +5 -0
- data/test/cases/callbacks_observers_test.rb +38 -0
- data/test/cases/connection_test_mysql.rb +1 -1
- data/test/cases/defaults_test.rb +32 -1
- data/test/cases/deprecated_finder_test.rb +0 -0
- data/test/cases/dirty_test.rb +13 -0
- data/test/cases/finder_test.rb +162 -12
- data/test/cases/fixtures_test.rb +32 -3
- data/test/cases/helper.rb +15 -0
- data/test/cases/i18n_test.rb +41 -0
- data/test/cases/inheritance_test.rb +2 -2
- data/test/cases/lifecycle_test.rb +0 -0
- data/test/cases/locking_test.rb +4 -9
- data/test/cases/method_scoping_test.rb +109 -2
- data/test/cases/migration_test.rb +43 -8
- data/test/cases/multiple_db_test.rb +25 -0
- data/test/cases/named_scope_test.rb +74 -0
- data/test/cases/pooled_connections_test.rb +103 -0
- data/test/cases/readonly_test.rb +0 -0
- data/test/cases/reflection_test.rb +11 -3
- data/test/cases/reload_models_test.rb +20 -0
- data/test/cases/sanitize_test.rb +25 -0
- data/test/cases/schema_authorization_test_postgresql.rb +2 -2
- data/test/cases/transactions_test.rb +62 -12
- data/test/cases/unconnected_test.rb +0 -0
- data/test/cases/validations_i18n_test.rb +921 -0
- data/test/cases/validations_test.rb +44 -33
- data/test/connections/native_mysql/connection.rb +1 -3
- data/test/fixtures/companies.yml +1 -0
- data/test/fixtures/customers.yml +10 -1
- data/test/fixtures/fixture_database.sqlite3 +0 -0
- data/test/fixtures/fixture_database_2.sqlite3 +0 -0
- data/test/fixtures/organizations.yml +5 -0
- data/test/migrations/broken/100_migration_that_raises_exception.rb +10 -0
- data/test/models/author.rb +3 -0
- data/test/models/category.rb +3 -0
- data/test/models/club.rb +6 -0
- data/test/models/company.rb +25 -1
- data/test/models/customer.rb +19 -1
- data/test/models/member.rb +2 -0
- data/test/models/member_detail.rb +4 -0
- data/test/models/organization.rb +4 -0
- data/test/models/parrot.rb +1 -0
- data/test/models/post.rb +3 -0
- data/test/models/reply.rb +0 -0
- data/test/models/topic.rb +3 -0
- data/test/schema/schema.rb +12 -1
- metadata +22 -10
- data/lib/active_record/vendor/mysql.rb +0 -1214
- data/test/cases/adapter_test_sqlserver.rb +0 -95
- data/test/cases/table_name_test_sqlserver.rb +0 -23
- data/test/cases/threaded_connections_test.rb +0 -48
- data/test/schema/sqlserver_specific_schema.rb +0 -5
@@ -25,6 +25,11 @@ class ActiveSchemaTest < ActiveRecord::TestCase
|
|
25
25
|
assert_equal "CREATE DATABASE `aimonetti` DEFAULT CHARACTER SET `latin1`", create_database(:aimonetti, {:charset => 'latin1'})
|
26
26
|
assert_equal "CREATE DATABASE `matt_aimonetti` DEFAULT CHARACTER SET `big5` COLLATE `big5_chinese_ci`", create_database(:matt_aimonetti, {:charset => :big5, :collation => :big5_chinese_ci})
|
27
27
|
end
|
28
|
+
|
29
|
+
def test_recreate_mysql_database_with_encoding
|
30
|
+
create_database(:luca, {:charset => 'latin1'})
|
31
|
+
assert_equal "CREATE DATABASE `luca` DEFAULT CHARACTER SET `latin1`", recreate_database(:luca, {:charset => 'latin1'})
|
32
|
+
end
|
28
33
|
end
|
29
34
|
|
30
35
|
def test_add_column
|
data/test/cases/adapter_test.rb
CHANGED
@@ -65,6 +65,12 @@ class AdapterTest < ActiveRecord::TestCase
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
+
if current_adapter?(:PostgreSQLAdapter)
|
69
|
+
def test_encoding
|
70
|
+
assert_not_nil @connection.encoding
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
68
74
|
def test_table_alias
|
69
75
|
def @connection.test_table_alias_length() 10; end
|
70
76
|
class << @connection
|
@@ -107,6 +107,45 @@ class AggregationsTest < ActiveRecord::TestCase
|
|
107
107
|
customers(:david).gps_location = nil
|
108
108
|
assert_equal nil, customers(:david).gps_location
|
109
109
|
end
|
110
|
+
|
111
|
+
def test_custom_constructor
|
112
|
+
assert_equal 'Barney GUMBLE', customers(:barney).fullname.to_s
|
113
|
+
assert_kind_of Fullname, customers(:barney).fullname
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_custom_converter
|
117
|
+
customers(:barney).fullname = 'Barnoit Gumbleau'
|
118
|
+
assert_equal 'Barnoit GUMBLEAU', customers(:barney).fullname.to_s
|
119
|
+
assert_kind_of Fullname, customers(:barney).fullname
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class DeprecatedAggregationsTest < ActiveRecord::TestCase
|
124
|
+
class Person < ActiveRecord::Base; end
|
125
|
+
|
126
|
+
def test_conversion_block_is_deprecated
|
127
|
+
assert_deprecated 'conversion block has been deprecated' do
|
128
|
+
Person.composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount)) { |balance| balance.to_money }
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_conversion_block_used_when_converter_option_is_nil
|
133
|
+
assert_deprecated 'conversion block has been deprecated' do
|
134
|
+
Person.composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount)) { |balance| balance.to_money }
|
135
|
+
end
|
136
|
+
assert_raise(NoMethodError) { Person.new.balance = 5 }
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_converter_option_overrides_conversion_block
|
140
|
+
assert_deprecated 'conversion block has been deprecated' do
|
141
|
+
Person.composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount), :converter => Proc.new { |balance| Money.new(balance) }) { |balance| balance.to_money }
|
142
|
+
end
|
143
|
+
|
144
|
+
person = Person.new
|
145
|
+
assert_nothing_raised { person.balance = 5 }
|
146
|
+
assert_equal 5, person.balance.amount
|
147
|
+
assert_kind_of Money, person.balance
|
148
|
+
end
|
110
149
|
end
|
111
150
|
|
112
151
|
class OverridingAggregationsTest < ActiveRecord::TestCase
|
@@ -428,4 +428,14 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
|
|
428
428
|
assert log.valid?
|
429
429
|
assert log.save
|
430
430
|
end
|
431
|
+
|
432
|
+
def test_belongs_to_proxy_should_not_respond_to_private_methods
|
433
|
+
assert_raises(NoMethodError) { companies(:first_firm).private_method }
|
434
|
+
assert_raises(NoMethodError) { companies(:second_client).firm.private_method }
|
435
|
+
end
|
436
|
+
|
437
|
+
def test_belongs_to_proxy_should_respond_to_private_methods_via_send
|
438
|
+
companies(:first_firm).send(:private_method)
|
439
|
+
companies(:second_client).firm.send(:private_method)
|
440
|
+
end
|
431
441
|
end
|
@@ -1,5 +1,20 @@
|
|
1
1
|
require 'cases/helper'
|
2
2
|
|
3
|
+
module Remembered
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
base.class_eval do
|
7
|
+
after_create :remember
|
8
|
+
protected
|
9
|
+
def remember; self.class.remembered << self; end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def remembered; @@remembered ||= []; end
|
15
|
+
def rand; @@remembered.rand; end
|
16
|
+
end
|
17
|
+
end
|
3
18
|
|
4
19
|
class ShapeExpression < ActiveRecord::Base
|
5
20
|
belongs_to :shape, :polymorphic => true
|
@@ -8,26 +23,33 @@ end
|
|
8
23
|
|
9
24
|
class Circle < ActiveRecord::Base
|
10
25
|
has_many :shape_expressions, :as => :shape
|
26
|
+
include Remembered
|
11
27
|
end
|
12
28
|
class Square < ActiveRecord::Base
|
13
29
|
has_many :shape_expressions, :as => :shape
|
30
|
+
include Remembered
|
14
31
|
end
|
15
32
|
class Triangle < ActiveRecord::Base
|
16
33
|
has_many :shape_expressions, :as => :shape
|
34
|
+
include Remembered
|
17
35
|
end
|
18
36
|
class PaintColor < ActiveRecord::Base
|
19
37
|
has_many :shape_expressions, :as => :paint
|
20
38
|
belongs_to :non_poly, :foreign_key => "non_poly_one_id", :class_name => "NonPolyOne"
|
39
|
+
include Remembered
|
21
40
|
end
|
22
41
|
class PaintTexture < ActiveRecord::Base
|
23
42
|
has_many :shape_expressions, :as => :paint
|
24
43
|
belongs_to :non_poly, :foreign_key => "non_poly_two_id", :class_name => "NonPolyTwo"
|
44
|
+
include Remembered
|
25
45
|
end
|
26
46
|
class NonPolyOne < ActiveRecord::Base
|
27
47
|
has_many :paint_colors
|
48
|
+
include Remembered
|
28
49
|
end
|
29
50
|
class NonPolyTwo < ActiveRecord::Base
|
30
51
|
has_many :paint_textures
|
52
|
+
include Remembered
|
31
53
|
end
|
32
54
|
|
33
55
|
|
@@ -49,23 +71,19 @@ class EagerLoadPolyAssocsTest < ActiveRecord::TestCase
|
|
49
71
|
end
|
50
72
|
|
51
73
|
|
52
|
-
# meant to be supplied as an ID, never returns 0
|
53
|
-
def rand_simple
|
54
|
-
val = (NUM_SIMPLE_OBJS * rand).round
|
55
|
-
val == 0 ? 1 : val
|
56
|
-
end
|
57
|
-
|
58
74
|
def generate_test_object_graphs
|
59
75
|
1.upto(NUM_SIMPLE_OBJS) do
|
60
76
|
[Circle, Square, Triangle, NonPolyOne, NonPolyTwo].map(&:create!)
|
61
77
|
end
|
62
|
-
1.upto(NUM_SIMPLE_OBJS) do
|
63
|
-
PaintColor.create!(:non_poly_one_id =>
|
64
|
-
PaintTexture.create!(:non_poly_two_id =>
|
78
|
+
1.upto(NUM_SIMPLE_OBJS) do
|
79
|
+
PaintColor.create!(:non_poly_one_id => NonPolyOne.rand.id)
|
80
|
+
PaintTexture.create!(:non_poly_two_id => NonPolyTwo.rand.id)
|
65
81
|
end
|
66
|
-
1.upto(NUM_SHAPE_EXPRESSIONS) do
|
67
|
-
|
68
|
-
|
82
|
+
1.upto(NUM_SHAPE_EXPRESSIONS) do
|
83
|
+
shape_type = [Circle, Square, Triangle].rand
|
84
|
+
paint_type = [PaintColor, PaintTexture].rand
|
85
|
+
ShapeExpression.create!(:shape_type => shape_type.to_s, :shape_id => shape_type.rand.id,
|
86
|
+
:paint_type => paint_type.to_s, :paint_id => paint_type.rand.id)
|
69
87
|
end
|
70
88
|
end
|
71
89
|
|
@@ -18,7 +18,7 @@ require 'models/developer'
|
|
18
18
|
require 'models/project'
|
19
19
|
|
20
20
|
class EagerAssociationTest < ActiveRecord::TestCase
|
21
|
-
fixtures :posts, :comments, :authors, :categories, :categories_posts,
|
21
|
+
fixtures :posts, :comments, :authors, :author_addresses, :categories, :categories_posts,
|
22
22
|
:companies, :accounts, :tags, :taggings, :people, :readers,
|
23
23
|
:owners, :pets, :author_favorites, :jobs, :references, :subscribers, :subscriptions, :books,
|
24
24
|
:developers, :projects, :developers_projects
|
@@ -111,6 +111,46 @@ class EagerAssociationTest < ActiveRecord::TestCase
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
+
def test_finding_with_includes_on_has_many_association_with_same_include_includes_only_once
|
115
|
+
author_id = authors(:david).id
|
116
|
+
author = assert_queries(3) { Author.find(author_id, :include => {:posts_with_comments => :comments}) } # find the author, then find the posts, then find the comments
|
117
|
+
author.posts_with_comments.each do |post_with_comments|
|
118
|
+
assert_equal post_with_comments.comments.length, post_with_comments.comments.count
|
119
|
+
assert_equal nil, post_with_comments.comments.uniq!
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_finding_with_includes_on_has_one_assocation_with_same_include_includes_only_once
|
124
|
+
author = authors(:david)
|
125
|
+
post = author.post_about_thinking_with_last_comment
|
126
|
+
last_comment = post.last_comment
|
127
|
+
author = assert_queries(3) { Author.find(author.id, :include => {:post_about_thinking_with_last_comment => :last_comment})} # find the author, then find the posts, then find the comments
|
128
|
+
assert_no_queries do
|
129
|
+
assert_equal post, author.post_about_thinking_with_last_comment
|
130
|
+
assert_equal last_comment, author.post_about_thinking_with_last_comment.last_comment
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_finding_with_includes_on_belongs_to_association_with_same_include_includes_only_once
|
135
|
+
post = posts(:welcome)
|
136
|
+
author = post.author
|
137
|
+
author_address = author.author_address
|
138
|
+
post = assert_queries(3) { Post.find(post.id, :include => {:author_with_address => :author_address}) } # find the post, then find the author, then find the address
|
139
|
+
assert_no_queries do
|
140
|
+
assert_equal author, post.author_with_address
|
141
|
+
assert_equal author_address, post.author_with_address.author_address
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_finding_with_includes_on_null_belongs_to_association_with_same_include_includes_only_once
|
146
|
+
post = posts(:welcome)
|
147
|
+
post.update_attributes!(:author => nil)
|
148
|
+
post = assert_queries(2) { Post.find(post.id, :include => {:author_with_address => :author_address}) } # find the post, then find the author which is null so no query for the address
|
149
|
+
assert_no_queries do
|
150
|
+
assert_equal nil, post.author_with_address
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
114
154
|
def test_loading_from_an_association
|
115
155
|
posts = authors(:david).posts.find(:all, :include => :comments, :order => "posts.id")
|
116
156
|
assert_equal 2, posts.first.comments.size
|
@@ -267,14 +307,23 @@ class EagerAssociationTest < ActiveRecord::TestCase
|
|
267
307
|
end
|
268
308
|
|
269
309
|
def test_eager_with_has_many_through
|
270
|
-
posts_with_comments = people(:michael).posts.find(:all, :include => :comments)
|
271
|
-
posts_with_author = people(:michael).posts.find(:all, :include => :author )
|
272
|
-
posts_with_comments_and_author = people(:michael).posts.find(:all, :include => [ :comments, :author ])
|
310
|
+
posts_with_comments = people(:michael).posts.find(:all, :include => :comments, :order => 'posts.id')
|
311
|
+
posts_with_author = people(:michael).posts.find(:all, :include => :author, :order => 'posts.id')
|
312
|
+
posts_with_comments_and_author = people(:michael).posts.find(:all, :include => [ :comments, :author ], :order => 'posts.id')
|
273
313
|
assert_equal 2, posts_with_comments.inject(0) { |sum, post| sum += post.comments.size }
|
274
314
|
assert_equal authors(:david), assert_no_queries { posts_with_author.first.author }
|
275
315
|
assert_equal authors(:david), assert_no_queries { posts_with_comments_and_author.first.author }
|
276
316
|
end
|
277
317
|
|
318
|
+
def test_eager_with_has_many_through_a_belongs_to_association
|
319
|
+
author = authors(:mary)
|
320
|
+
post = Post.create!(:author => author, :title => "TITLE", :body => "BODY")
|
321
|
+
author.author_favorites.create(:favorite_author_id => 1)
|
322
|
+
author.author_favorites.create(:favorite_author_id => 2)
|
323
|
+
posts_with_author_favorites = author.posts.find(:all, :include => :author_favorites)
|
324
|
+
assert_no_queries { posts_with_author_favorites.first.author_favorites.first.author_id }
|
325
|
+
end
|
326
|
+
|
278
327
|
def test_eager_with_has_many_through_an_sti_join_model
|
279
328
|
author = Author.find(:first, :include => :special_post_comments, :order => 'authors.id')
|
280
329
|
assert_equal [comments(:does_it_hurt)], assert_no_queries { author.special_post_comments }
|
@@ -618,7 +667,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
|
|
618
667
|
end
|
619
668
|
|
620
669
|
def test_count_with_include
|
621
|
-
if current_adapter?(:
|
670
|
+
if current_adapter?(:SybaseAdapter)
|
622
671
|
assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "len(comments.body) > 15")
|
623
672
|
elsif current_adapter?(:OpenBaseAdapter)
|
624
673
|
assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "length(FETCHBLOB(comments.body)) > 15")
|
@@ -68,6 +68,16 @@ class DeveloperWithSymbolsForKeys < ActiveRecord::Base
|
|
68
68
|
:foreign_key => "developer_id"
|
69
69
|
end
|
70
70
|
|
71
|
+
class DeveloperWithCounterSQL < ActiveRecord::Base
|
72
|
+
set_table_name 'developers'
|
73
|
+
has_and_belongs_to_many :projects,
|
74
|
+
:class_name => "DeveloperWithCounterSQL",
|
75
|
+
:join_table => "developers_projects",
|
76
|
+
:association_foreign_key => "project_id",
|
77
|
+
:foreign_key => "developer_id",
|
78
|
+
:counter_sql => 'SELECT COUNT(*) AS count_all FROM projects INNER JOIN developers_projects ON projects.id = developers_projects.project_id WHERE developers_projects.developer_id =#{id}'
|
79
|
+
end
|
80
|
+
|
71
81
|
class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
|
72
82
|
fixtures :accounts, :companies, :categories, :posts, :categories_posts, :developers, :projects, :developers_projects,
|
73
83
|
:parrots, :pirates, :treasures, :price_estimates, :tags, :taggings
|
@@ -223,10 +233,10 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
|
|
223
233
|
devel = Developer.find(1)
|
224
234
|
proj = assert_no_queries { devel.projects.build("name" => "Projekt") }
|
225
235
|
assert !devel.projects.loaded?
|
226
|
-
|
236
|
+
|
227
237
|
assert_equal devel.projects.last, proj
|
228
238
|
assert devel.projects.loaded?
|
229
|
-
|
239
|
+
|
230
240
|
assert proj.new_record?
|
231
241
|
devel.save
|
232
242
|
assert !proj.new_record?
|
@@ -251,10 +261,10 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
|
|
251
261
|
devel = Developer.find(1)
|
252
262
|
proj = devel.projects.create("name" => "Projekt")
|
253
263
|
assert !devel.projects.loaded?
|
254
|
-
|
264
|
+
|
255
265
|
assert_equal devel.projects.last, proj
|
256
|
-
assert devel.projects.loaded?
|
257
|
-
|
266
|
+
assert !devel.projects.loaded?
|
267
|
+
|
258
268
|
assert !proj.new_record?
|
259
269
|
assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated
|
260
270
|
end
|
@@ -274,10 +284,10 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
|
|
274
284
|
|
275
285
|
def test_creation_respects_hash_condition
|
276
286
|
post = categories(:general).post_with_conditions.build(:body => '')
|
277
|
-
|
287
|
+
|
278
288
|
assert post.save
|
279
289
|
assert_equal 'Yet Another Testing Title', post.title
|
280
|
-
|
290
|
+
|
281
291
|
another_post = categories(:general).post_with_conditions.create(:body => '')
|
282
292
|
|
283
293
|
assert !another_post.new_record?
|
@@ -288,7 +298,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
|
|
288
298
|
dev = developers(:jamis)
|
289
299
|
dev.projects << projects(:active_record)
|
290
300
|
dev.projects << projects(:active_record)
|
291
|
-
|
301
|
+
|
292
302
|
assert_equal 3, dev.projects.size
|
293
303
|
assert_equal 1, dev.projects.uniq.size
|
294
304
|
end
|
@@ -415,13 +425,13 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
|
|
415
425
|
project.developers.class # force load target
|
416
426
|
|
417
427
|
developer = project.developers.first
|
418
|
-
|
428
|
+
|
419
429
|
assert_no_queries do
|
420
430
|
assert project.developers.loaded?
|
421
431
|
assert project.developers.include?(developer)
|
422
432
|
end
|
423
433
|
end
|
424
|
-
|
434
|
+
|
425
435
|
def test_include_checks_if_record_exists_if_target_not_loaded
|
426
436
|
project = projects(:active_record)
|
427
437
|
developer = project.developers.first
|
@@ -636,11 +646,39 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
|
|
636
646
|
assert_equal 3, Developer.find(:all, :include => {:projects => :developers}, :conditions => 'developers_projects_join.joined_on IS NOT NULL', :group => group.join(",")).size
|
637
647
|
end
|
638
648
|
|
649
|
+
def test_find_grouped
|
650
|
+
all_posts_from_category1 = Post.find(:all, :conditions => "category_id = 1", :joins => :categories)
|
651
|
+
grouped_posts_of_category1 = Post.find(:all, :conditions => "category_id = 1", :group => "author_id", :select => 'count(posts.id) as posts_count', :joins => :categories)
|
652
|
+
assert_equal 4, all_posts_from_category1.size
|
653
|
+
assert_equal 1, grouped_posts_of_category1.size
|
654
|
+
end
|
655
|
+
|
656
|
+
def test_find_scoped_grouped
|
657
|
+
assert_equal 4, categories(:general).posts_gruoped_by_title.size
|
658
|
+
assert_equal 1, categories(:technology).posts_gruoped_by_title.size
|
659
|
+
end
|
660
|
+
|
639
661
|
def test_get_ids
|
640
662
|
assert_equal projects(:active_record, :action_controller).map(&:id).sort, developers(:david).project_ids.sort
|
641
663
|
assert_equal [projects(:active_record).id], developers(:jamis).project_ids
|
642
664
|
end
|
643
665
|
|
666
|
+
def test_get_ids_for_loaded_associations
|
667
|
+
developer = developers(:david)
|
668
|
+
developer.projects(true)
|
669
|
+
assert_queries(0) do
|
670
|
+
developer.project_ids
|
671
|
+
developer.project_ids
|
672
|
+
end
|
673
|
+
end
|
674
|
+
|
675
|
+
def test_get_ids_for_unloaded_associations_does_not_load_them
|
676
|
+
developer = developers(:david)
|
677
|
+
assert !developer.projects.loaded?
|
678
|
+
assert_equal projects(:active_record, :action_controller).map(&:id).sort, developer.project_ids.sort
|
679
|
+
assert !developer.projects.loaded?
|
680
|
+
end
|
681
|
+
|
644
682
|
def test_assign_ids
|
645
683
|
developer = Developer.new("name" => "Joe")
|
646
684
|
developer.project_ids = projects(:active_record, :action_controller).map(&:id)
|
@@ -703,4 +741,33 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
|
|
703
741
|
# due to Unknown column 'authors.id'
|
704
742
|
assert Category.find(1).posts_with_authors_sorted_by_author_id.find_by_title('Welcome to the weblog')
|
705
743
|
end
|
744
|
+
|
745
|
+
def test_counting_on_habtm_association_and_not_array
|
746
|
+
david = Developer.find(1)
|
747
|
+
# Extra parameter just to make sure we aren't falling back to
|
748
|
+
# Array#count in Ruby >=1.8.7, which would raise an ArgumentError
|
749
|
+
assert_nothing_raised { david.projects.count(:all, :conditions => '1=1') }
|
750
|
+
end
|
751
|
+
|
752
|
+
def test_count
|
753
|
+
david = Developer.find(1)
|
754
|
+
assert_equal 2, david.projects.count
|
755
|
+
end
|
756
|
+
|
757
|
+
def test_count_with_counter_sql
|
758
|
+
developer = DeveloperWithCounterSQL.create(:name => 'tekin')
|
759
|
+
developer.project_ids = [projects(:active_record).id]
|
760
|
+
developer.save
|
761
|
+
developer.reload
|
762
|
+
assert_equal 1, developer.projects.count
|
763
|
+
end
|
764
|
+
|
765
|
+
uses_mocha 'mocking Post.transaction' do
|
766
|
+
def test_association_proxy_transaction_method_starts_transaction_in_association_class
|
767
|
+
Post.expects(:transaction)
|
768
|
+
Category.find(:first).posts.transaction do
|
769
|
+
# nothing
|
770
|
+
end
|
771
|
+
end
|
772
|
+
end
|
706
773
|
end
|
@@ -135,6 +135,10 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
|
|
135
135
|
assert_equal "Microsoft", Firm.find(:first).clients_like_ms_with_hash_conditions.first.name
|
136
136
|
end
|
137
137
|
|
138
|
+
def test_finding_using_primary_key
|
139
|
+
assert_equal "Summit", Firm.find(:first).clients_using_primary_key.first.name
|
140
|
+
end
|
141
|
+
|
138
142
|
def test_finding_using_sql
|
139
143
|
firm = Firm.find(:first)
|
140
144
|
first_client = firm.clients_using_sql.first
|
@@ -244,6 +248,13 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
|
|
244
248
|
assert_equal 1, grouped_clients_of_firm1.size
|
245
249
|
end
|
246
250
|
|
251
|
+
def test_find_scoped_grouped
|
252
|
+
assert_equal 1, companies(:first_firm).clients_grouped_by_firm_id.size
|
253
|
+
assert_equal 1, companies(:first_firm).clients_grouped_by_firm_id.length
|
254
|
+
assert_equal 2, companies(:first_firm).clients_grouped_by_name.size
|
255
|
+
assert_equal 2, companies(:first_firm).clients_grouped_by_name.length
|
256
|
+
end
|
257
|
+
|
247
258
|
def test_adding
|
248
259
|
force_signal37_to_load_all_clients_of_firm
|
249
260
|
natural = Client.new("name" => "Natural Company")
|
@@ -380,7 +391,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
|
|
380
391
|
company = companies(:first_firm)
|
381
392
|
new_client = assert_no_queries { company.clients_of_firm.build("name" => "Another Client") }
|
382
393
|
assert !company.clients_of_firm.loaded?
|
383
|
-
|
394
|
+
|
384
395
|
assert_equal "Another Client", new_client.name
|
385
396
|
assert new_client.new_record?
|
386
397
|
assert_equal new_client, company.clients_of_firm.last
|
@@ -412,7 +423,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
|
|
412
423
|
def test_build_many
|
413
424
|
company = companies(:first_firm)
|
414
425
|
new_clients = assert_no_queries { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) }
|
415
|
-
|
426
|
+
|
416
427
|
assert_equal 2, new_clients.size
|
417
428
|
company.name += '-changed'
|
418
429
|
assert_queries(3) { assert company.save }
|
@@ -651,10 +662,10 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
|
|
651
662
|
|
652
663
|
def test_creation_respects_hash_condition
|
653
664
|
ms_client = companies(:first_firm).clients_like_ms_with_hash_conditions.build
|
654
|
-
|
665
|
+
|
655
666
|
assert ms_client.save
|
656
667
|
assert_equal 'Microsoft', ms_client.name
|
657
|
-
|
668
|
+
|
658
669
|
another_ms_client = companies(:first_firm).clients_like_ms_with_hash_conditions.create
|
659
670
|
|
660
671
|
assert !another_ms_client.new_record?
|
@@ -826,6 +837,29 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
|
|
826
837
|
assert_equal [companies(:first_client).id, companies(:second_client).id], companies(:first_firm).client_ids
|
827
838
|
end
|
828
839
|
|
840
|
+
def test_get_ids_for_loaded_associations
|
841
|
+
company = companies(:first_firm)
|
842
|
+
company.clients(true)
|
843
|
+
assert_queries(0) do
|
844
|
+
company.client_ids
|
845
|
+
company.client_ids
|
846
|
+
end
|
847
|
+
end
|
848
|
+
|
849
|
+
def test_get_ids_for_unloaded_associations_does_not_load_them
|
850
|
+
company = companies(:first_firm)
|
851
|
+
assert !company.clients.loaded?
|
852
|
+
assert_equal [companies(:first_client).id, companies(:second_client).id], company.client_ids
|
853
|
+
assert !company.clients.loaded?
|
854
|
+
end
|
855
|
+
|
856
|
+
def test_get_ids_for_unloaded_finder_sql_associations_loads_them
|
857
|
+
company = companies(:first_firm)
|
858
|
+
assert !company.clients_using_sql.loaded?
|
859
|
+
assert_equal [companies(:second_client).id], company.clients_using_sql_ids
|
860
|
+
assert company.clients_using_sql.loaded?
|
861
|
+
end
|
862
|
+
|
829
863
|
def test_assign_ids
|
830
864
|
firm = Firm.new("name" => "Apple")
|
831
865
|
firm.client_ids = [companies(:first_client).id, companies(:second_client).id]
|
@@ -896,7 +930,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
|
|
896
930
|
assert_equal 4, authors(:david).limited_comments.find(:all, :conditions => "comments.type = 'SpecialComment'", :limit => 9_000).length
|
897
931
|
assert_equal 4, authors(:david).limited_comments.find_all_by_type('SpecialComment', :limit => 9_000).length
|
898
932
|
end
|
899
|
-
|
933
|
+
|
900
934
|
def test_find_all_include_over_the_same_table_for_through
|
901
935
|
assert_equal 2, people(:michael).posts.find(:all, :include => :people).length
|
902
936
|
end
|
@@ -933,13 +967,13 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
|
|
933
967
|
def test_include_loads_collection_if_target_uses_finder_sql
|
934
968
|
firm = companies(:first_firm)
|
935
969
|
client = firm.clients_using_sql.first
|
936
|
-
|
970
|
+
|
937
971
|
firm.reload
|
938
972
|
assert ! firm.clients_using_sql.loaded?
|
939
973
|
assert firm.clients_using_sql.include?(client)
|
940
974
|
assert firm.clients_using_sql.loaded?
|
941
975
|
end
|
942
|
-
|
976
|
+
|
943
977
|
|
944
978
|
def test_include_returns_false_for_non_matching_record_to_verify_scoping
|
945
979
|
firm = companies(:first_firm)
|
@@ -982,6 +1016,19 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
|
|
982
1016
|
assert firm.clients.loaded?
|
983
1017
|
end
|
984
1018
|
|
1019
|
+
def test_calling_first_or_last_on_existing_record_with_create_should_not_load_association
|
1020
|
+
firm = companies(:first_firm)
|
1021
|
+
firm.clients.create(:name => 'Foo')
|
1022
|
+
assert !firm.clients.loaded?
|
1023
|
+
|
1024
|
+
assert_queries 2 do
|
1025
|
+
firm.clients.first
|
1026
|
+
firm.clients.last
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
assert !firm.clients.loaded?
|
1030
|
+
end
|
1031
|
+
|
985
1032
|
def test_calling_first_or_last_on_new_record_should_not_run_queries
|
986
1033
|
firm = Firm.new
|
987
1034
|
|
@@ -1031,4 +1078,24 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
|
|
1031
1078
|
ActiveRecord::Base.store_full_sti_class = old
|
1032
1079
|
end
|
1033
1080
|
|
1081
|
+
uses_mocha 'mocking Comment.transaction' do
|
1082
|
+
def test_association_proxy_transaction_method_starts_transaction_in_association_class
|
1083
|
+
Comment.expects(:transaction)
|
1084
|
+
Post.find(:first).comments.transaction do
|
1085
|
+
# nothing
|
1086
|
+
end
|
1087
|
+
end
|
1088
|
+
end
|
1089
|
+
|
1090
|
+
def test_sending_new_to_association_proxy_should_have_same_effect_as_calling_new
|
1091
|
+
client_association = companies(:first_firm).clients
|
1092
|
+
assert_equal client_association.new.attributes, client_association.send(:new).attributes
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
def test_respond_to_private_class_methods
|
1096
|
+
client_association = companies(:first_firm).clients
|
1097
|
+
assert !client_association.respond_to?(:private_method)
|
1098
|
+
assert client_association.respond_to?(:private_method, true)
|
1099
|
+
end
|
1034
1100
|
end
|
1101
|
+
|