activerecord 1.13.2 → 1.14.0
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 +452 -10
- data/RUNNING_UNIT_TESTS +1 -1
- data/lib/active_record.rb +5 -2
- data/lib/active_record/acts/list.rb +1 -1
- data/lib/active_record/acts/tree.rb +29 -25
- data/lib/active_record/aggregations.rb +3 -2
- data/lib/active_record/associations.rb +783 -337
- data/lib/active_record/associations/association_collection.rb +7 -12
- data/lib/active_record/associations/association_proxy.rb +62 -24
- data/lib/active_record/associations/belongs_to_association.rb +27 -46
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +38 -38
- data/lib/active_record/associations/has_many_association.rb +61 -56
- data/lib/active_record/associations/has_many_through_association.rb +144 -0
- data/lib/active_record/associations/has_one_association.rb +22 -16
- data/lib/active_record/base.rb +482 -182
- data/lib/active_record/calculations.rb +225 -0
- data/lib/active_record/callbacks.rb +7 -7
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +162 -47
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +21 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +34 -2
- data/lib/active_record/connection_adapters/db2_adapter.rb +107 -61
- data/lib/active_record/connection_adapters/mysql_adapter.rb +29 -6
- data/lib/active_record/connection_adapters/openbase_adapter.rb +349 -0
- data/lib/active_record/connection_adapters/{oci_adapter.rb → oracle_adapter.rb} +125 -59
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +24 -21
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +47 -8
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +36 -16
- data/lib/active_record/connection_adapters/sybase_adapter.rb +684 -0
- data/lib/active_record/fixtures.rb +42 -17
- data/lib/active_record/locking.rb +36 -15
- data/lib/active_record/migration.rb +111 -8
- data/lib/active_record/observer.rb +25 -1
- data/lib/active_record/reflection.rb +103 -41
- data/lib/active_record/schema.rb +2 -2
- data/lib/active_record/schema_dumper.rb +55 -18
- data/lib/active_record/timestamp.rb +6 -6
- data/lib/active_record/validations.rb +65 -40
- data/lib/active_record/vendor/db2.rb +10 -5
- data/lib/active_record/vendor/simple.rb +693 -702
- data/lib/active_record/version.rb +2 -2
- data/rakefile +4 -4
- data/test/aaa_create_tables_test.rb +25 -6
- data/test/abstract_unit.rb +39 -1
- data/test/adapter_test.rb +31 -4
- data/test/associations_cascaded_eager_loading_test.rb +106 -0
- data/test/associations_go_eager_test.rb +85 -16
- data/test/associations_join_model_test.rb +338 -0
- data/test/associations_test.rb +129 -50
- data/test/base_test.rb +204 -49
- data/test/binary_test.rb +1 -1
- data/test/calculations_test.rb +169 -0
- data/test/callbacks_test.rb +5 -23
- data/test/class_inheritable_attributes_test.rb +1 -1
- data/test/column_alias_test.rb +1 -1
- data/test/connections/native_mysql/connection.rb +1 -0
- data/test/connections/native_openbase/connection.rb +22 -0
- data/test/connections/{native_oci → native_oracle}/connection.rb +7 -9
- data/test/connections/native_sqlite/connection.rb +1 -1
- data/test/connections/native_sqlite3/connection.rb +1 -0
- data/test/connections/native_sqlite3/in_memory_connection.rb +1 -0
- data/test/connections/native_sybase/connection.rb +24 -0
- data/test/defaults_test.rb +18 -0
- data/test/deprecated_associations_test.rb +2 -2
- data/test/deprecated_finder_test.rb +0 -6
- data/test/finder_test.rb +26 -23
- data/test/fixtures/accounts.yml +10 -0
- data/test/fixtures/author.rb +31 -6
- data/test/fixtures/author_favorites.yml +4 -0
- data/test/fixtures/categories/special_categories.yml +9 -0
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
- data/test/fixtures/categories_posts.yml +4 -0
- data/test/fixtures/categorization.rb +5 -0
- data/test/fixtures/categorizations.yml +11 -0
- data/test/fixtures/category.rb +6 -0
- data/test/fixtures/company.rb +17 -5
- data/test/fixtures/company_in_module.rb +19 -5
- data/test/fixtures/db_definitions/db2.drop.sql +3 -0
- data/test/fixtures/db_definitions/db2.sql +121 -100
- data/test/fixtures/db_definitions/db22.sql +2 -2
- data/test/fixtures/db_definitions/firebird.drop.sql +4 -0
- data/test/fixtures/db_definitions/firebird.sql +26 -0
- data/test/fixtures/db_definitions/mysql.drop.sql +3 -0
- data/test/fixtures/db_definitions/mysql.sql +21 -1
- data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase.sql +282 -0
- data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase2.sql +7 -0
- data/test/fixtures/db_definitions/{oci.drop.sql → oracle.drop.sql} +6 -0
- data/test/fixtures/db_definitions/{oci.sql → oracle.sql} +25 -4
- data/test/fixtures/db_definitions/{oci2.drop.sql → oracle2.drop.sql} +0 -0
- data/test/fixtures/db_definitions/{oci2.sql → oracle2.sql} +0 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +4 -0
- data/test/fixtures/db_definitions/postgresql.sql +22 -1
- data/test/fixtures/db_definitions/schema.rb +32 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +3 -0
- data/test/fixtures/db_definitions/sqlite.sql +18 -0
- data/test/fixtures/db_definitions/sqlserver.drop.sql +3 -0
- data/test/fixtures/db_definitions/sqlserver.sql +23 -3
- data/test/fixtures/db_definitions/sybase.drop.sql +31 -0
- data/test/fixtures/db_definitions/sybase.sql +204 -0
- data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
- data/test/fixtures/db_definitions/sybase2.sql +5 -0
- data/test/fixtures/developers.yml +6 -1
- data/test/fixtures/developers_projects.yml +4 -0
- data/test/fixtures/funny_jokes.yml +14 -0
- data/test/fixtures/joke.rb +6 -0
- data/test/fixtures/legacy_thing.rb +3 -0
- data/test/fixtures/legacy_things.yml +3 -0
- data/test/fixtures/mixin.rb +1 -1
- data/test/fixtures/person.rb +4 -1
- data/test/fixtures/post.rb +26 -1
- data/test/fixtures/project.rb +1 -0
- data/test/fixtures/reader.rb +4 -0
- data/test/fixtures/readers.yml +4 -0
- data/test/fixtures/reply.rb +2 -1
- data/test/fixtures/tag.rb +5 -0
- data/test/fixtures/tagging.rb +6 -0
- data/test/fixtures/taggings.yml +18 -0
- data/test/fixtures/tags.yml +7 -0
- data/test/fixtures/tasks.yml +2 -2
- data/test/fixtures/topic.rb +2 -2
- data/test/fixtures/topics.yml +1 -0
- data/test/fixtures_test.rb +47 -13
- data/test/inheritance_test.rb +2 -2
- data/test/locking_test.rb +15 -1
- data/test/method_scoping_test.rb +248 -13
- data/test/migration_test.rb +68 -11
- data/test/mixin_nested_set_test.rb +1 -1
- data/test/modules_test.rb +6 -1
- data/test/readonly_test.rb +1 -1
- data/test/reflection_test.rb +63 -9
- data/test/schema_dumper_test.rb +41 -0
- data/test/{synonym_test_oci.rb → synonym_test_oracle.rb} +1 -1
- data/test/threaded_connections_test.rb +10 -0
- data/test/unconnected_test.rb +12 -5
- data/test/validations_test.rb +197 -10
- metadata +295 -260
- data/test/fixtures/db_definitions/create_oracle_db.bat +0 -0
- data/test/fixtures/db_definitions/create_oracle_db.sh +0 -0
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
@@ -0,0 +1,338 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/tag'
|
3
|
+
require 'fixtures/tagging'
|
4
|
+
require 'fixtures/post'
|
5
|
+
require 'fixtures/comment'
|
6
|
+
require 'fixtures/author'
|
7
|
+
require 'fixtures/category'
|
8
|
+
require 'fixtures/categorization'
|
9
|
+
|
10
|
+
class AssociationsJoinModelTest < Test::Unit::TestCase
|
11
|
+
self.use_transactional_fixtures = false
|
12
|
+
fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites
|
13
|
+
|
14
|
+
def test_has_many
|
15
|
+
assert_equal categories(:general), authors(:david).categories.first
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_has_many_inherited
|
19
|
+
assert_equal categories(:sti_test), authors(:mary).categories.first
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_inherited_has_many
|
23
|
+
assert_equal authors(:mary), categories(:sti_test).authors.first
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_polymorphic_has_many
|
27
|
+
assert_equal taggings(:welcome_general), posts(:welcome).taggings.first
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_polymorphic_has_one
|
31
|
+
assert_equal taggings(:welcome_general), posts(:welcome).tagging
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_polymorphic_belongs_to
|
35
|
+
assert_equal posts(:welcome), posts(:welcome).taggings.first.taggable
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_polymorphic_has_many_going_through_join_model
|
39
|
+
assert_equal tags(:general), tag = posts(:welcome).tags.first
|
40
|
+
assert_no_queries do
|
41
|
+
tag.tagging
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_count_polymorphic_has_many
|
46
|
+
assert_equal 1, posts(:welcome).taggings.count
|
47
|
+
assert_equal 1, posts(:welcome).tags.count
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_polymorphic_has_many_going_through_join_model_with_find
|
51
|
+
assert_equal tags(:general), tag = posts(:welcome).tags.find(:first)
|
52
|
+
assert_no_queries do
|
53
|
+
tag.tagging
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_polymorphic_has_many_going_through_join_model_with_include_on_source_reflection
|
58
|
+
assert_equal tags(:general), tag = posts(:welcome).funky_tags.first
|
59
|
+
assert_no_queries do
|
60
|
+
tag.tagging
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_polymorphic_has_many_going_through_join_model_with_include_on_source_reflection_with_find
|
65
|
+
assert_equal tags(:general), tag = posts(:welcome).funky_tags.find(:first)
|
66
|
+
assert_no_queries do
|
67
|
+
tag.tagging
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_polymorphic_has_many_going_through_join_model_with_disabled_include
|
72
|
+
assert_equal tags(:general), tag = posts(:welcome).tags.add_joins_and_select.first
|
73
|
+
assert_queries 1 do
|
74
|
+
tag.tagging
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_polymorphic_has_many_going_through_join_model_with_custom_select_and_joins
|
79
|
+
assert_equal tags(:general), tag = posts(:welcome).tags.add_joins_and_select.first
|
80
|
+
tag.author_id
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_polymorphic_has_many_going_through_join_model_with_custom_foreign_key
|
84
|
+
assert_equal tags(:misc), taggings(:welcome_general).super_tag
|
85
|
+
assert_equal tags(:misc), posts(:welcome).super_tags.first
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_polymorphic_has_many_create_model_with_inheritance_and_custom_base_class
|
89
|
+
post = SubStiPost.create :title => 'SubStiPost', :body => 'SubStiPost body'
|
90
|
+
assert_instance_of SubStiPost, post
|
91
|
+
|
92
|
+
tagging = tags(:misc).taggings.create(:taggable => post)
|
93
|
+
assert_equal "SubStiPost", tagging.taggable_type
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_polymorphic_has_many_going_through_join_model_with_inheritance
|
97
|
+
assert_equal tags(:general), posts(:thinking).tags.first
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_polymorphic_has_many_going_through_join_model_with_inheritance_with_custom_class_name
|
101
|
+
assert_equal tags(:general), posts(:thinking).funky_tags.first
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_polymorphic_has_many_create_model_with_inheritance
|
105
|
+
post = posts(:thinking)
|
106
|
+
assert_instance_of SpecialPost, post
|
107
|
+
|
108
|
+
tagging = tags(:misc).taggings.create(:taggable => post)
|
109
|
+
assert_equal "Post", tagging.taggable_type
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_polymorphic_has_one_create_model_with_inheritance
|
113
|
+
tagging = tags(:misc).create_tagging(:taggable => posts(:thinking))
|
114
|
+
assert_equal "Post", tagging.taggable_type
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_set_polymorphic_has_many
|
118
|
+
tagging = tags(:misc).taggings.create
|
119
|
+
posts(:thinking).taggings << tagging
|
120
|
+
assert_equal "Post", tagging.taggable_type
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_set_polymorphic_has_one
|
124
|
+
tagging = tags(:misc).taggings.create
|
125
|
+
posts(:thinking).tagging = tagging
|
126
|
+
assert_equal "Post", tagging.taggable_type
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_create_polymorphic_has_many_with_scope
|
130
|
+
old_count = posts(:welcome).taggings.count
|
131
|
+
tagging = posts(:welcome).taggings.create(:tag => tags(:misc))
|
132
|
+
assert_equal "Post", tagging.taggable_type
|
133
|
+
assert_equal old_count+1, posts(:welcome).taggings.count
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_create_polymorphic_has_one_with_scope
|
137
|
+
old_count = Tagging.count
|
138
|
+
tagging = posts(:welcome).tagging.create(:tag => tags(:misc))
|
139
|
+
assert_equal "Post", tagging.taggable_type
|
140
|
+
assert_equal old_count+1, Tagging.count
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_delete_polymorphic_has_many_with_delete_all
|
144
|
+
assert_equal 1, posts(:welcome).taggings.count
|
145
|
+
posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyDeleteAll'
|
146
|
+
post = find_post_with_dependency(1, :has_many, :taggings, :delete_all)
|
147
|
+
|
148
|
+
old_count = Tagging.count
|
149
|
+
post.destroy
|
150
|
+
assert_equal old_count-1, Tagging.count
|
151
|
+
assert_equal 0, posts(:welcome).taggings.count
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_delete_polymorphic_has_many_with_destroy
|
155
|
+
assert_equal 1, posts(:welcome).taggings.count
|
156
|
+
posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyDestroy'
|
157
|
+
post = find_post_with_dependency(1, :has_many, :taggings, :destroy)
|
158
|
+
|
159
|
+
old_count = Tagging.count
|
160
|
+
post.destroy
|
161
|
+
assert_equal old_count-1, Tagging.count
|
162
|
+
assert_equal 0, posts(:welcome).taggings.count
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_delete_polymorphic_has_many_with_nullify
|
166
|
+
assert_equal 1, posts(:welcome).taggings.count
|
167
|
+
posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyNullify'
|
168
|
+
post = find_post_with_dependency(1, :has_many, :taggings, :nullify)
|
169
|
+
|
170
|
+
old_count = Tagging.count
|
171
|
+
post.destroy
|
172
|
+
assert_equal old_count, Tagging.count
|
173
|
+
assert_equal 0, posts(:welcome).taggings.count
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_delete_polymorphic_has_one_with_destroy
|
177
|
+
assert posts(:welcome).tagging
|
178
|
+
posts(:welcome).tagging.update_attribute :taggable_type, 'PostWithHasOneDestroy'
|
179
|
+
post = find_post_with_dependency(1, :has_one, :tagging, :destroy)
|
180
|
+
|
181
|
+
old_count = Tagging.count
|
182
|
+
post.destroy
|
183
|
+
assert_equal old_count-1, Tagging.count
|
184
|
+
assert_nil posts(:welcome).tagging(true)
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_delete_polymorphic_has_one_with_nullify
|
188
|
+
assert posts(:welcome).tagging
|
189
|
+
posts(:welcome).tagging.update_attribute :taggable_type, 'PostWithHasOneNullify'
|
190
|
+
post = find_post_with_dependency(1, :has_one, :tagging, :nullify)
|
191
|
+
|
192
|
+
old_count = Tagging.count
|
193
|
+
post.destroy
|
194
|
+
assert_equal old_count, Tagging.count
|
195
|
+
assert_nil posts(:welcome).tagging(true)
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_has_many_with_piggyback
|
199
|
+
assert_equal "2", categories(:sti_test).authors.first.post_id.to_s
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_include_has_many_through
|
203
|
+
posts = Post.find(:all, :order => 'posts.id')
|
204
|
+
posts_with_authors = Post.find(:all, :include => :authors, :order => 'posts.id')
|
205
|
+
assert_equal posts.length, posts_with_authors.length
|
206
|
+
posts.length.times do |i|
|
207
|
+
assert_equal posts[i].authors.length, assert_no_queries { posts_with_authors[i].authors.length }
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_include_polymorphic_has_many_through
|
212
|
+
posts = Post.find(:all, :order => 'posts.id')
|
213
|
+
posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
|
214
|
+
assert_equal posts.length, posts_with_tags.length
|
215
|
+
posts.length.times do |i|
|
216
|
+
assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length }
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_include_polymorphic_has_many
|
221
|
+
posts = Post.find(:all, :order => 'posts.id')
|
222
|
+
posts_with_taggings = Post.find(:all, :include => :taggings, :order => 'posts.id')
|
223
|
+
assert_equal posts.length, posts_with_taggings.length
|
224
|
+
posts.length.times do |i|
|
225
|
+
assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length }
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_has_many_find_all
|
230
|
+
assert_equal [categories(:general)], authors(:david).categories.find(:all)
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_has_many_find_first
|
234
|
+
assert_equal categories(:general), authors(:david).categories.find(:first)
|
235
|
+
end
|
236
|
+
|
237
|
+
def test_has_many_find_conditions
|
238
|
+
assert_equal categories(:general), authors(:david).categories.find(:first, :conditions => "categories.name = 'General'")
|
239
|
+
assert_equal nil, authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'")
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_has_many_class_methods_called_by_method_missing
|
243
|
+
assert_equal categories(:general), authors(:david).categories.find_all_by_name('General').first
|
244
|
+
# assert_equal nil, authors(:david).categories.find_by_name('Technology')
|
245
|
+
end
|
246
|
+
|
247
|
+
def test_has_many_going_through_join_model_with_custom_foreign_key
|
248
|
+
assert_equal [], posts(:thinking).authors
|
249
|
+
assert_equal [authors(:mary)], posts(:authorless).authors
|
250
|
+
end
|
251
|
+
|
252
|
+
def test_belongs_to_polymorphic_with_counter_cache
|
253
|
+
assert_equal 0, posts(:welcome)[:taggings_count]
|
254
|
+
tagging = posts(:welcome).taggings.create(:tag => tags(:general))
|
255
|
+
assert_equal 1, posts(:welcome, :reload)[:taggings_count]
|
256
|
+
tagging.destroy
|
257
|
+
assert posts(:welcome, :reload)[:taggings_count].zero?
|
258
|
+
end
|
259
|
+
|
260
|
+
def test_unavailable_through_reflection
|
261
|
+
assert_raises (ActiveRecord::HasManyThroughAssociationNotFoundError) { authors(:david).nothings }
|
262
|
+
end
|
263
|
+
|
264
|
+
def test_has_many_through_join_model_with_conditions
|
265
|
+
assert_equal [], posts(:welcome).invalid_taggings
|
266
|
+
assert_equal [], posts(:welcome).invalid_tags
|
267
|
+
end
|
268
|
+
|
269
|
+
def test_has_many_polymorphic
|
270
|
+
assert_raises ActiveRecord::HasManyThroughAssociationPolymorphicError do
|
271
|
+
assert_equal [posts(:welcome), posts(:thinking)], tags(:general).taggables
|
272
|
+
end
|
273
|
+
assert_raises ActiveRecord::EagerLoadPolymorphicError do
|
274
|
+
assert_equal [posts(:welcome), posts(:thinking)], tags(:general).taggings.find(:all, :include => :taggable)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_has_many_through_has_many_find_all
|
279
|
+
assert_equal comments(:greetings), authors(:david).comments.find(:all, :order => 'comments.id').first
|
280
|
+
end
|
281
|
+
|
282
|
+
def test_has_many_through_has_many_find_all_with_custom_class
|
283
|
+
assert_equal comments(:greetings), authors(:david).funky_comments.find(:all, :order => 'comments.id').first
|
284
|
+
end
|
285
|
+
|
286
|
+
def test_has_many_through_has_many_find_first
|
287
|
+
assert_equal comments(:greetings), authors(:david).comments.find(:first, :order => 'comments.id')
|
288
|
+
end
|
289
|
+
|
290
|
+
def test_has_many_through_has_many_find_conditions
|
291
|
+
assert_equal comments(:does_it_hurt), authors(:david).comments.find(:first, :conditions => "comments.type='SpecialComment'", :order => 'comments.id')
|
292
|
+
end
|
293
|
+
|
294
|
+
def test_has_many_through_has_many_find_by_id
|
295
|
+
assert_equal comments(:more_greetings), authors(:david).comments.find(2)
|
296
|
+
end
|
297
|
+
|
298
|
+
def test_eager_load_has_many_through_has_many
|
299
|
+
author = Author.find :first, :conditions => ['name = ?', 'David'], :include => :comments, :order => 'comments.id'
|
300
|
+
SpecialComment.new; VerySpecialComment.new
|
301
|
+
assert_no_queries do
|
302
|
+
assert_equal [1,2,3,5,6,7,8,9,10], author.comments.collect(&:id)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def test_eager_belongs_to_and_has_one_not_singularized
|
307
|
+
assert_nothing_raised do
|
308
|
+
Author.find(:first, :include => :author_address)
|
309
|
+
AuthorAddress.find(:first, :include => :author)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
def test_self_referential_has_many_through
|
314
|
+
assert_equal [authors(:mary)], authors(:david).favorite_authors
|
315
|
+
assert_equal [], authors(:mary).favorite_authors
|
316
|
+
end
|
317
|
+
|
318
|
+
def test_add_to_self_referential_has_many_through
|
319
|
+
new_author = Author.create(:name => "Bob")
|
320
|
+
authors(:david).author_favorites.create :favorite_author => new_author
|
321
|
+
assert_equal new_author, authors(:david).reload.favorite_authors.first
|
322
|
+
end
|
323
|
+
|
324
|
+
def test_has_many_through_uses_correct_attributes
|
325
|
+
assert_nil posts(:thinking).tags.find_by_name("General").attributes["tag_id"]
|
326
|
+
end
|
327
|
+
|
328
|
+
private
|
329
|
+
# create dynamic Post models to allow different dependency options
|
330
|
+
def find_post_with_dependency(post_id, association, association_name, dependency)
|
331
|
+
class_name = "PostWith#{association.to_s.classify}#{dependency.to_s.classify}"
|
332
|
+
Post.find(post_id).update_attribute :type, class_name
|
333
|
+
klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
|
334
|
+
klass.set_table_name 'posts'
|
335
|
+
klass.send(association, association_name, :as => :taggable, :dependent => dependency)
|
336
|
+
klass.find(post_id)
|
337
|
+
end
|
338
|
+
end
|
data/test/associations_test.rb
CHANGED
@@ -79,6 +79,7 @@ class HasOneAssociationsTest < Test::Unit::TestCase
|
|
79
79
|
|
80
80
|
def test_triple_equality
|
81
81
|
assert Account === companies(:first_firm).account
|
82
|
+
assert companies(:first_firm).account === Account
|
82
83
|
end
|
83
84
|
|
84
85
|
def test_type_mismatch
|
@@ -157,6 +158,15 @@ class HasOneAssociationsTest < Test::Unit::TestCase
|
|
157
158
|
assert_equal "can't be empty", account.errors.on("credit_limit")
|
158
159
|
end
|
159
160
|
|
161
|
+
def test_build_association_twice_without_saving_affects_nothing
|
162
|
+
count_of_account = Account.count
|
163
|
+
firm = Firm.find(:first)
|
164
|
+
account1 = firm.build_account("credit_limit" => 1000)
|
165
|
+
account2 = firm.build_account("credit_limit" => 2000)
|
166
|
+
|
167
|
+
assert_equal count_of_account, Account.count
|
168
|
+
end
|
169
|
+
|
160
170
|
def test_create_association
|
161
171
|
firm = Firm.new("name" => "GlobalMegaCorp")
|
162
172
|
firm.save
|
@@ -280,6 +290,17 @@ class HasManyAssociationsTest < Test::Unit::TestCase
|
|
280
290
|
assert_equal 2, Firm.find(:first).clients.length
|
281
291
|
end
|
282
292
|
|
293
|
+
def test_find_many_with_merged_options
|
294
|
+
assert_equal 1, companies(:first_firm).limited_clients.size
|
295
|
+
assert_equal 1, companies(:first_firm).limited_clients.find(:all).size
|
296
|
+
assert_equal 2, companies(:first_firm).limited_clients.find(:all, :limit => nil).size
|
297
|
+
end
|
298
|
+
|
299
|
+
def test_triple_equality
|
300
|
+
assert !(Array === Firm.find(:first).clients)
|
301
|
+
assert Firm.find(:first).clients === Array
|
302
|
+
end
|
303
|
+
|
283
304
|
def test_finding_default_orders
|
284
305
|
assert_equal "Summit", Firm.find(:first).clients.first.name
|
285
306
|
end
|
@@ -641,7 +662,7 @@ class HasManyAssociationsTest < Test::Unit::TestCase
|
|
641
662
|
def test_three_levels_of_dependence
|
642
663
|
topic = Topic.create "title" => "neat and simple"
|
643
664
|
reply = topic.replies.create "title" => "neat and simple", "content" => "still digging it"
|
644
|
-
silly_reply = reply.
|
665
|
+
silly_reply = reply.replies.create "title" => "neat and simple", "content" => "ain't complaining"
|
645
666
|
|
646
667
|
assert_nothing_raised { topic.destroy }
|
647
668
|
end
|
@@ -664,7 +685,6 @@ class HasManyAssociationsTest < Test::Unit::TestCase
|
|
664
685
|
assert_equal num_accounts - 1, Account.count
|
665
686
|
end
|
666
687
|
|
667
|
-
|
668
688
|
def test_depends_and_nullify
|
669
689
|
num_accounts = Account.count
|
670
690
|
num_companies = Company.count
|
@@ -747,6 +767,11 @@ class BelongsToAssociationsTest < Test::Unit::TestCase
|
|
747
767
|
assert_nothing_raised { account.firm = account.firm }
|
748
768
|
end
|
749
769
|
|
770
|
+
def test_triple_equality
|
771
|
+
assert Client.find(3).firm === Firm
|
772
|
+
assert Firm === Client.find(3).firm
|
773
|
+
end
|
774
|
+
|
750
775
|
def test_type_mismatch
|
751
776
|
assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = 1 }
|
752
777
|
assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = Project.find(1) }
|
@@ -804,6 +829,38 @@ class BelongsToAssociationsTest < Test::Unit::TestCase
|
|
804
829
|
assert_equal 0, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply deleted"
|
805
830
|
end
|
806
831
|
|
832
|
+
def test_belongs_to_counter_with_reassigning
|
833
|
+
t1 = Topic.create("title" => "t1")
|
834
|
+
t2 = Topic.create("title" => "t2")
|
835
|
+
r1 = Reply.new("title" => "r1", "content" => "r1")
|
836
|
+
r1.topic = t1
|
837
|
+
|
838
|
+
assert r1.save
|
839
|
+
assert_equal 1, Topic.find(t1.id).replies.size
|
840
|
+
assert_equal 0, Topic.find(t2.id).replies.size
|
841
|
+
|
842
|
+
r1.topic = Topic.find(t2.id)
|
843
|
+
|
844
|
+
assert r1.save
|
845
|
+
assert_equal 0, Topic.find(t1.id).replies.size
|
846
|
+
assert_equal 1, Topic.find(t2.id).replies.size
|
847
|
+
|
848
|
+
r1.topic = nil
|
849
|
+
|
850
|
+
assert_equal 0, Topic.find(t1.id).replies.size
|
851
|
+
assert_equal 0, Topic.find(t2.id).replies.size
|
852
|
+
|
853
|
+
r1.topic = t1
|
854
|
+
|
855
|
+
assert_equal 1, Topic.find(t1.id).replies.size
|
856
|
+
assert_equal 0, Topic.find(t2.id).replies.size
|
857
|
+
|
858
|
+
r1.destroy
|
859
|
+
|
860
|
+
assert_equal 0, Topic.find(t1.id).replies.size
|
861
|
+
assert_equal 0, Topic.find(t2.id).replies.size
|
862
|
+
end
|
863
|
+
|
807
864
|
def test_assignment_before_parent_saved
|
808
865
|
client = Client.find(:first)
|
809
866
|
apple = Firm.new("name" => "Apple")
|
@@ -860,21 +917,32 @@ class BelongsToAssociationsTest < Test::Unit::TestCase
|
|
860
917
|
assert_not_nil computer.developer, ":foreign key == attribute didn't lock up" # '
|
861
918
|
end
|
862
919
|
|
863
|
-
def
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
apple.clients.to_s
|
868
|
-
assert_equal 1, apple.clients.size, "Created one client"
|
920
|
+
def test_counter_cache
|
921
|
+
topic = Topic.create :title => "Zoom-zoom-zoom"
|
922
|
+
assert_equal 0, topic[:replies_count]
|
869
923
|
|
870
|
-
|
871
|
-
|
924
|
+
reply = Reply.create(:title => "re: zoom", :content => "speedy quick!")
|
925
|
+
reply.topic = topic
|
926
|
+
|
927
|
+
assert_equal 1, topic.reload[:replies_count]
|
928
|
+
assert_equal 1, topic.replies.size
|
929
|
+
|
930
|
+
topic[:replies_count] = 15
|
931
|
+
assert_equal 15, topic.replies.size
|
932
|
+
end
|
933
|
+
|
934
|
+
def test_custom_counter_cache
|
935
|
+
reply = Reply.create(:title => "re: zoom", :content => "speedy quick!")
|
936
|
+
assert_equal 0, reply[:replies_count]
|
937
|
+
|
938
|
+
silly = SillyReply.create(:title => "gaga", :content => "boo-boo")
|
939
|
+
silly.reply = reply
|
872
940
|
|
873
|
-
|
874
|
-
assert_equal
|
941
|
+
assert_equal 1, reply.reload[:replies_count]
|
942
|
+
assert_equal 1, reply.replies.size
|
875
943
|
|
876
|
-
|
877
|
-
assert_equal
|
944
|
+
reply[:replies_count] = 17
|
945
|
+
assert_equal 17, reply.replies.size
|
878
946
|
end
|
879
947
|
|
880
948
|
def test_store_two_association_with_one_save
|
@@ -1022,10 +1090,15 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
|
|
1022
1090
|
|
1023
1091
|
active_record = Project.find(1)
|
1024
1092
|
assert !active_record.developers.empty?
|
1025
|
-
assert_equal
|
1093
|
+
assert_equal 3, active_record.developers.size
|
1026
1094
|
assert active_record.developers.include?(david)
|
1027
1095
|
end
|
1028
1096
|
|
1097
|
+
def test_triple_equality
|
1098
|
+
assert !(Array === Developer.find(1).projects)
|
1099
|
+
assert Developer.find(1).projects === Array
|
1100
|
+
end
|
1101
|
+
|
1029
1102
|
def test_adding_single
|
1030
1103
|
jamis = Developer.find(2)
|
1031
1104
|
jamis.projects.reload # causing the collection to load
|
@@ -1149,7 +1222,6 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
|
|
1149
1222
|
no_of_devels = Developer.count
|
1150
1223
|
no_of_projects = Project.count
|
1151
1224
|
now = Date.today
|
1152
|
-
sqlnow = Time.now.strftime("%Y/%m/%d 00:00:00")
|
1153
1225
|
ken = Developer.new("name" => "Ken")
|
1154
1226
|
ken.projects.push_with_attributes( Project.find(1), :joined_on => now )
|
1155
1227
|
p = Project.new("name" => "Foomatic")
|
@@ -1164,12 +1236,22 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
|
|
1164
1236
|
assert_equal 2, ken.projects(true).size
|
1165
1237
|
|
1166
1238
|
kenReloaded = Developer.find_by_name 'Ken'
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1239
|
+
kenReloaded.projects.each {|prj| assert_date_from_db(now, prj.joined_on)}
|
1240
|
+
end
|
1241
|
+
|
1242
|
+
def test_habtm_saving_multiple_relationships
|
1243
|
+
new_project = Project.new("name" => "Grimetime")
|
1244
|
+
amount_of_developers = 4
|
1245
|
+
developers = (0..amount_of_developers).collect {|i| Developer.create(:name => "JME #{i}") }
|
1246
|
+
|
1247
|
+
new_project.developer_ids = [developers[0].id, developers[1].id]
|
1248
|
+
new_project.developers_with_callback_ids = [developers[2].id, developers[3].id]
|
1249
|
+
assert new_project.save
|
1250
|
+
|
1251
|
+
new_project.reload
|
1252
|
+
assert_equal amount_of_developers, new_project.developers.size
|
1253
|
+
amount_of_developers.times do |i|
|
1254
|
+
assert_equal developers[i].name, new_project.developers[i].name
|
1173
1255
|
end
|
1174
1256
|
end
|
1175
1257
|
|
@@ -1200,7 +1282,7 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
|
|
1200
1282
|
def test_uniq_before_the_fact
|
1201
1283
|
projects(:active_record).developers << developers(:jamis)
|
1202
1284
|
projects(:active_record).developers << developers(:david)
|
1203
|
-
assert_equal
|
1285
|
+
assert_equal 3, projects(:active_record, :reload).developers.size
|
1204
1286
|
end
|
1205
1287
|
|
1206
1288
|
def test_deleting
|
@@ -1208,13 +1290,13 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
|
|
1208
1290
|
active_record = Project.find(1)
|
1209
1291
|
david.projects.reload
|
1210
1292
|
assert_equal 2, david.projects.size
|
1211
|
-
assert_equal
|
1293
|
+
assert_equal 3, active_record.developers.size
|
1212
1294
|
|
1213
1295
|
david.projects.delete(active_record)
|
1214
1296
|
|
1215
1297
|
assert_equal 1, david.projects.size
|
1216
1298
|
assert_equal 1, david.projects(true).size
|
1217
|
-
assert_equal
|
1299
|
+
assert_equal 2, active_record.developers(true).size
|
1218
1300
|
end
|
1219
1301
|
|
1220
1302
|
def test_deleting_array
|
@@ -1229,16 +1311,16 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
|
|
1229
1311
|
david = Developer.find(1)
|
1230
1312
|
active_record = Project.find(1)
|
1231
1313
|
active_record.developers.reload
|
1232
|
-
assert_equal
|
1314
|
+
assert_equal 3, active_record.developers_by_sql.size
|
1233
1315
|
|
1234
1316
|
active_record.developers_by_sql.delete(david)
|
1235
|
-
assert_equal
|
1317
|
+
assert_equal 2, active_record.developers_by_sql(true).size
|
1236
1318
|
end
|
1237
1319
|
|
1238
1320
|
def test_deleting_array_with_sql
|
1239
1321
|
active_record = Project.find(1)
|
1240
1322
|
active_record.developers.reload
|
1241
|
-
assert_equal
|
1323
|
+
assert_equal 3, active_record.developers_by_sql.size
|
1242
1324
|
|
1243
1325
|
active_record.developers_by_sql.delete(Developer.find(:all))
|
1244
1326
|
assert_equal 0, active_record.developers_by_sql(true).size
|
@@ -1261,13 +1343,7 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
|
|
1261
1343
|
end
|
1262
1344
|
|
1263
1345
|
def test_additional_columns_from_join_table
|
1264
|
-
|
1265
|
-
# so the time is in the string and incorrectly formatted
|
1266
|
-
if current_adapter?(:SQLServerAdapter)
|
1267
|
-
assert_equal Time.mktime(2004, 10, 10).strftime("%Y/%m/%d 00:00:00"), Developer.find(1).projects.first.joined_on.strftime("%Y/%m/%d 00:00:00")
|
1268
|
-
else
|
1269
|
-
assert_equal Date.new(2004, 10, 10).to_s, Developer.find(1).projects.first.joined_on.to_s
|
1270
|
-
end
|
1346
|
+
assert_date_from_db Date.new(2004, 10, 10), Developer.find(1).projects.first.joined_on
|
1271
1347
|
end
|
1272
1348
|
|
1273
1349
|
def test_destroy_all
|
@@ -1282,26 +1358,20 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
|
|
1282
1358
|
def test_rich_association
|
1283
1359
|
jamis = developers(:jamis)
|
1284
1360
|
jamis.projects.push_with_attributes(projects(:action_controller), :joined_on => Date.today)
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
assert_equal Time.now.strftime("%Y/%m/%d 00:00:00"), jamis.projects.select { |p| p.name == projects(:action_controller).name }.first.joined_on.strftime("%Y/%m/%d 00:00:00")
|
1289
|
-
assert_equal Time.now.strftime("%Y/%m/%d 00:00:00"), developers(:jamis).projects.select { |p| p.name == projects(:action_controller).name }.first.joined_on.strftime("%Y/%m/%d 00:00:00")
|
1290
|
-
else
|
1291
|
-
assert_equal Date.today.to_s, jamis.projects.select { |p| p.name == projects(:action_controller).name }.first.joined_on.to_s
|
1292
|
-
assert_equal Date.today.to_s, developers(:jamis).projects.select { |p| p.name == projects(:action_controller).name }.first.joined_on.to_s
|
1293
|
-
end
|
1361
|
+
|
1362
|
+
assert_date_from_db Date.today, jamis.projects.select { |p| p.name == projects(:action_controller).name }.first.joined_on
|
1363
|
+
assert_date_from_db Date.today, developers(:jamis).projects.select { |p| p.name == projects(:action_controller).name }.first.joined_on
|
1294
1364
|
end
|
1295
1365
|
|
1296
1366
|
def test_associations_with_conditions
|
1297
|
-
assert_equal
|
1367
|
+
assert_equal 3, projects(:active_record).developers.size
|
1298
1368
|
assert_equal 1, projects(:active_record).developers_named_david.size
|
1299
1369
|
|
1300
1370
|
assert_equal developers(:david), projects(:active_record).developers_named_david.find(developers(:david).id)
|
1301
1371
|
assert_equal developers(:david), projects(:active_record).salaried_developers.find(developers(:david).id)
|
1302
1372
|
|
1303
1373
|
projects(:active_record).developers_named_david.clear
|
1304
|
-
assert_equal
|
1374
|
+
assert_equal 2, projects(:active_record, :reload).developers.size
|
1305
1375
|
end
|
1306
1376
|
|
1307
1377
|
def test_find_in_association
|
@@ -1326,6 +1396,11 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
|
|
1326
1396
|
assert_equal developers(:david), projects(:active_record).developers_with_finder_sql.find(developers(:david).id.to_s), "SQL find"
|
1327
1397
|
end
|
1328
1398
|
|
1399
|
+
def test_find_with_merged_options
|
1400
|
+
assert_equal 1, projects(:active_record).limited_developers.size
|
1401
|
+
assert_equal 1, projects(:active_record).limited_developers.find(:all).size
|
1402
|
+
assert_equal 3, projects(:active_record).limited_developers.find(:all, :limit => nil).size
|
1403
|
+
end
|
1329
1404
|
|
1330
1405
|
def test_new_with_values_in_collection
|
1331
1406
|
jamis = DeveloperForProjectWithAfterCreateHook.find_by_name('Jamis')
|
@@ -1339,12 +1414,12 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
|
|
1339
1414
|
assert project.developers.include?(david)
|
1340
1415
|
end
|
1341
1416
|
|
1342
|
-
def
|
1417
|
+
def test_find_in_association_with_options
|
1343
1418
|
developers = projects(:active_record).developers.find(:all)
|
1344
|
-
assert_equal
|
1419
|
+
assert_equal 3, developers.size
|
1345
1420
|
|
1346
|
-
assert_equal developers(:
|
1347
|
-
assert_equal developers(:jamis),
|
1421
|
+
assert_equal developers(:poor_jamis), projects(:active_record).developers.find(:first, :conditions => "salary < 10000")
|
1422
|
+
assert_equal developers(:jamis), projects(:active_record).developers.find(:first, :order => "salary DESC")
|
1348
1423
|
end
|
1349
1424
|
|
1350
1425
|
def test_replace_with_less
|
@@ -1394,4 +1469,8 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
|
|
1394
1469
|
AND developer_id = #{developer.id}
|
1395
1470
|
end_sql
|
1396
1471
|
end
|
1472
|
+
|
1473
|
+
def test_join_table_alias
|
1474
|
+
assert_equal 3, Developer.find(:all, :include => {:projects => :developers}, :conditions => 'developers_projects_join.joined_on IS NOT NULL').size
|
1475
|
+
end
|
1397
1476
|
end
|