ibm_db 2.5.26-universal-darwin-14 → 2.6.1-universal-darwin-14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +11 -0
  3. data/MANIFEST +14 -14
  4. data/README +225 -225
  5. data/ext/Makefile.nt32 +181 -181
  6. data/ext/Makefile.nt32.191 +212 -212
  7. data/ext/extconf.rb +264 -261
  8. data/ext/extconf_MacOS.rb +269 -0
  9. data/ext/ibm_db.c +11879 -11793
  10. data/ext/ruby_ibm_db.h +241 -240
  11. data/ext/ruby_ibm_db_cli.c +851 -845
  12. data/ext/ruby_ibm_db_cli.h +500 -489
  13. data/init.rb +41 -41
  14. data/lib/IBM_DB.rb +27 -19
  15. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +3339 -3289
  16. data/lib/active_record/connection_adapters/ibmdb_adapter.rb +1 -1
  17. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -328
  18. data/test/cases/adapter_test.rb +207 -207
  19. data/test/cases/associations/belongs_to_associations_test.rb +711 -711
  20. data/test/cases/associations/cascaded_eager_loading_test.rb +181 -181
  21. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +851 -851
  22. data/test/cases/associations/join_model_test.rb +743 -743
  23. data/test/cases/attribute_methods_test.rb +822 -822
  24. data/test/cases/base_test.rb +2133 -2133
  25. data/test/cases/calculations_test.rb +482 -482
  26. data/test/cases/migration_test.rb +2408 -2408
  27. data/test/cases/persistence_test.rb +642 -642
  28. data/test/cases/query_cache_test.rb +257 -257
  29. data/test/cases/relations_test.rb +1182 -1182
  30. data/test/cases/schema_dumper_test.rb +256 -256
  31. data/test/cases/transaction_callbacks_test.rb +300 -300
  32. data/test/cases/validations/uniqueness_validation_test.rb +299 -299
  33. data/test/cases/xml_serialization_test.rb +408 -408
  34. data/test/config.yml +154 -154
  35. data/test/connections/native_ibm_db/connection.rb +43 -43
  36. data/test/ibm_db_test.rb +24 -24
  37. data/test/models/warehouse_thing.rb +4 -4
  38. data/test/schema/schema.rb +751 -751
  39. metadata +6 -8
  40. data/lib/linux/rb18x/ibm_db.bundle +0 -0
  41. data/lib/linux/rb19x/ibm_db.bundle +0 -0
  42. data/lib/linux/rb20x/ibm_db.bundle +0 -0
  43. data/lib/linux/rb21x/ibm_db.bundle +0 -0
@@ -1,743 +1,743 @@
1
- require "cases/helper"
2
- require 'active_support/core_ext/object/inclusion'
3
- require 'models/tag'
4
- require 'models/tagging'
5
- require 'models/post'
6
- require 'models/rating'
7
- require 'models/item'
8
- require 'models/comment'
9
- require 'models/author'
10
- require 'models/category'
11
- require 'models/categorization'
12
- require 'models/vertex'
13
- require 'models/edge'
14
- require 'models/book'
15
- require 'models/citation'
16
- require 'models/aircraft'
17
- require 'models/engine'
18
- require 'models/car'
19
-
20
- class AssociationsJoinModelTest < ActiveRecord::TestCase
21
- self.use_transactional_fixtures = false unless supports_savepoints?
22
-
23
- fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books,
24
- # Reload edges table from fixtures as otherwise repeated test was failing
25
- :edges
26
-
27
- def test_has_many
28
- assert authors(:david).categories.include?(categories(:general))
29
- end
30
-
31
- def test_has_many_inherited
32
- assert authors(:mary).categories.include?(categories(:sti_test))
33
- end
34
-
35
- def test_inherited_has_many
36
- assert categories(:sti_test).authors.include?(authors(:mary))
37
- end
38
-
39
- def test_has_many_uniq_through_join_model
40
- assert_equal 2, authors(:mary).categorized_posts.size
41
- assert_equal 1, authors(:mary).unique_categorized_posts.size
42
- end
43
-
44
- def test_has_many_uniq_through_count
45
- author = authors(:mary)
46
- assert !authors(:mary).unique_categorized_posts.loaded?
47
- assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count }
48
- assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count(:title) }
49
- assert_queries(1) { assert_equal 0, author.unique_categorized_posts.count(:title, :conditions => "title is NULL") }
50
- assert !authors(:mary).unique_categorized_posts.loaded?
51
- end
52
-
53
- def test_has_many_uniq_through_find
54
- assert_equal 1, authors(:mary).unique_categorized_posts.find(:all).size
55
- end
56
-
57
- def test_has_many_uniq_through_dynamic_find
58
- assert_equal 1, authors(:mary).unique_categorized_posts.find_all_by_title("So I was thinking").size
59
- end
60
-
61
- def test_polymorphic_has_many_going_through_join_model
62
- assert_equal tags(:general), tag = posts(:welcome).tags.first
63
- assert_no_queries do
64
- tag.tagging
65
- end
66
- end
67
-
68
- def test_count_polymorphic_has_many
69
- assert_equal 1, posts(:welcome).taggings.count
70
- assert_equal 1, posts(:welcome).tags.count
71
- end
72
-
73
- def test_polymorphic_has_many_going_through_join_model_with_find
74
- assert_equal tags(:general), tag = posts(:welcome).tags.find(:first)
75
- assert_no_queries do
76
- tag.tagging
77
- end
78
- end
79
-
80
- def test_polymorphic_has_many_going_through_join_model_with_include_on_source_reflection
81
- assert_equal tags(:general), tag = posts(:welcome).funky_tags.first
82
- assert_no_queries do
83
- tag.tagging
84
- end
85
- end
86
-
87
- def test_polymorphic_has_many_going_through_join_model_with_include_on_source_reflection_with_find
88
- assert_equal tags(:general), tag = posts(:welcome).funky_tags.find(:first)
89
- assert_no_queries do
90
- tag.tagging
91
- end
92
- end
93
-
94
- def test_polymorphic_has_many_going_through_join_model_with_custom_select_and_joins
95
- assert_equal tags(:general), tag = posts(:welcome).tags.add_joins_and_select.first
96
- assert_nothing_raised(NoMethodError) { tag.author_id }
97
- end
98
-
99
- def test_polymorphic_has_many_going_through_join_model_with_custom_foreign_key
100
- assert_equal tags(:misc), taggings(:welcome_general).super_tag
101
- assert_equal tags(:misc), posts(:welcome).super_tags.first
102
- end
103
-
104
- def test_polymorphic_has_many_create_model_with_inheritance_and_custom_base_class
105
- post = SubStiPost.create :title => 'SubStiPost', :body => 'SubStiPost body'
106
- assert_instance_of SubStiPost, post
107
-
108
- tagging = tags(:misc).taggings.create(:taggable => post)
109
- assert_equal "SubStiPost", tagging.taggable_type
110
- end
111
-
112
- def test_polymorphic_has_many_going_through_join_model_with_inheritance
113
- assert_equal tags(:general), posts(:thinking).tags.first
114
- end
115
-
116
- def test_polymorphic_has_many_going_through_join_model_with_inheritance_with_custom_class_name
117
- assert_equal tags(:general), posts(:thinking).funky_tags.first
118
- end
119
-
120
- def test_polymorphic_has_many_create_model_with_inheritance
121
- post = posts(:thinking)
122
- assert_instance_of SpecialPost, post
123
-
124
- tagging = tags(:misc).taggings.create(:taggable => post)
125
- assert_equal "Post", tagging.taggable_type
126
- end
127
-
128
- def test_polymorphic_has_one_create_model_with_inheritance
129
- tagging = tags(:misc).create_tagging(:taggable => posts(:thinking))
130
- assert_equal "Post", tagging.taggable_type
131
- end
132
-
133
- def test_set_polymorphic_has_many
134
- tagging = tags(:misc).taggings.create
135
- posts(:thinking).taggings << tagging
136
- assert_equal "Post", tagging.taggable_type
137
- end
138
-
139
- def test_set_polymorphic_has_one
140
- tagging = tags(:misc).taggings.create
141
- posts(:thinking).tagging = tagging
142
-
143
- assert_equal "Post", tagging.taggable_type
144
- assert_equal posts(:thinking).id, tagging.taggable_id
145
- assert_equal posts(:thinking), tagging.taggable
146
- end
147
-
148
- def test_set_polymorphic_has_one_on_new_record
149
- tagging = tags(:misc).taggings.create
150
- post = Post.new :title => "foo", :body => "bar"
151
- post.tagging = tagging
152
- post.save!
153
-
154
- assert_equal "Post", tagging.taggable_type
155
- assert_equal post.id, tagging.taggable_id
156
- assert_equal post, tagging.taggable
157
- end
158
-
159
- def test_create_polymorphic_has_many_with_scope
160
- old_count = posts(:welcome).taggings.count
161
- tagging = posts(:welcome).taggings.create(:tag => tags(:misc))
162
- assert_equal "Post", tagging.taggable_type
163
- assert_equal old_count+1, posts(:welcome).taggings.count
164
- end
165
-
166
- def test_create_bang_polymorphic_with_has_many_scope
167
- old_count = posts(:welcome).taggings.count
168
- tagging = posts(:welcome).taggings.create!(:tag => tags(:misc))
169
- assert_equal "Post", tagging.taggable_type
170
- assert_equal old_count+1, posts(:welcome).taggings.count
171
- end
172
-
173
- def test_create_polymorphic_has_one_with_scope
174
- old_count = Tagging.count
175
- tagging = posts(:welcome).create_tagging(:tag => tags(:misc))
176
- assert_equal "Post", tagging.taggable_type
177
- assert_equal old_count+1, Tagging.count
178
- end
179
-
180
- def test_delete_polymorphic_has_many_with_delete_all
181
- assert_equal 1, posts(:welcome).taggings.count
182
- posts(:welcome).taggings.first.update_column :taggable_type, 'PostWithHasManyDeleteAll'
183
- post = find_post_with_dependency(1, :has_many, :taggings, :delete_all)
184
-
185
- old_count = Tagging.count
186
- post.destroy
187
- assert_equal old_count-1, Tagging.count
188
- assert_equal 0, posts(:welcome).taggings.count
189
- end
190
-
191
- def test_delete_polymorphic_has_many_with_destroy
192
- assert_equal 1, posts(:welcome).taggings.count
193
- posts(:welcome).taggings.first.update_column :taggable_type, 'PostWithHasManyDestroy'
194
- post = find_post_with_dependency(1, :has_many, :taggings, :destroy)
195
-
196
- old_count = Tagging.count
197
- post.destroy
198
- assert_equal old_count-1, Tagging.count
199
- assert_equal 0, posts(:welcome).taggings.count
200
- end
201
-
202
- def test_delete_polymorphic_has_many_with_nullify
203
- assert_equal 1, posts(:welcome).taggings.count
204
- posts(:welcome).taggings.first.update_column :taggable_type, 'PostWithHasManyNullify'
205
- post = find_post_with_dependency(1, :has_many, :taggings, :nullify)
206
-
207
- old_count = Tagging.count
208
- post.destroy
209
- assert_equal old_count, Tagging.count
210
- assert_equal 0, posts(:welcome).taggings.count
211
- end
212
-
213
- def test_delete_polymorphic_has_one_with_destroy
214
- assert posts(:welcome).tagging
215
- posts(:welcome).tagging.update_column :taggable_type, 'PostWithHasOneDestroy'
216
- post = find_post_with_dependency(1, :has_one, :tagging, :destroy)
217
-
218
- old_count = Tagging.count
219
- post.destroy
220
- assert_equal old_count-1, Tagging.count
221
- assert_nil posts(:welcome).tagging(true)
222
- end
223
-
224
- def test_delete_polymorphic_has_one_with_nullify
225
- assert posts(:welcome).tagging
226
- posts(:welcome).tagging.update_column :taggable_type, 'PostWithHasOneNullify'
227
- post = find_post_with_dependency(1, :has_one, :tagging, :nullify)
228
-
229
- old_count = Tagging.count
230
- post.destroy
231
- assert_equal old_count, Tagging.count
232
- assert_nil posts(:welcome).tagging(true)
233
- end
234
-
235
- def test_has_many_with_piggyback
236
- assert_equal "2", categories(:sti_test).authors_with_select.first.post_id.to_s
237
- end
238
-
239
- def test_include_has_many_through
240
- posts = Post.find(:all, :order => 'posts.id')
241
- posts_with_authors = Post.find(:all, :include => :authors, :order => 'posts.id')
242
- assert_equal posts.length, posts_with_authors.length
243
- posts.length.times do |i|
244
- assert_equal posts[i].authors.length, assert_no_queries { posts_with_authors[i].authors.length }
245
- end
246
- end
247
-
248
- def test_include_polymorphic_has_one
249
- post = Post.find_by_id(posts(:welcome).id, :include => :tagging)
250
- tagging = taggings(:welcome_general)
251
- assert_no_queries do
252
- assert_equal tagging, post.tagging
253
- end
254
- end
255
-
256
- def test_include_polymorphic_has_one_defined_in_abstract_parent
257
- item = Item.find_by_id(items(:dvd).id, :include => :tagging)
258
- tagging = taggings(:godfather)
259
- assert_no_queries do
260
- assert_equal tagging, item.tagging
261
- end
262
- end
263
-
264
- def test_include_polymorphic_has_many_through
265
- posts = Post.find(:all, :order => 'posts.id')
266
- posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
267
- assert_equal posts.length, posts_with_tags.length
268
- posts.length.times do |i|
269
- assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length }
270
- end
271
- end
272
-
273
- def test_include_polymorphic_has_many
274
- posts = Post.find(:all, :order => 'posts.id')
275
- posts_with_taggings = Post.find(:all, :include => :taggings, :order => 'posts.id')
276
- assert_equal posts.length, posts_with_taggings.length
277
- posts.length.times do |i|
278
- assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length }
279
- end
280
- end
281
-
282
- def test_has_many_find_all
283
- assert_equal [categories(:general)], authors(:david).categories.find(:all)
284
- end
285
-
286
- def test_has_many_find_first
287
- assert_equal categories(:general), authors(:david).categories.find(:first)
288
- end
289
-
290
- def test_has_many_with_hash_conditions
291
- assert_equal categories(:general), authors(:david).categories_like_general.find(:first)
292
- end
293
-
294
- def test_has_many_find_conditions
295
- assert_equal categories(:general), authors(:david).categories.find(:first, :conditions => "categories.name = 'General'")
296
- assert_nil authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'")
297
- end
298
-
299
- def test_has_many_class_methods_called_by_method_missing
300
- assert_equal categories(:general), authors(:david).categories.find_all_by_name('General').first
301
- assert_nil authors(:david).categories.find_by_name('Technology')
302
- end
303
-
304
- def test_has_many_array_methods_called_by_method_missing
305
- assert authors(:david).categories.any? { |category| category.name == 'General' }
306
- assert_nothing_raised { authors(:david).categories.sort }
307
- end
308
-
309
- def test_has_many_going_through_join_model_with_custom_foreign_key
310
- assert_equal [authors(:bob)], posts(:thinking).authors
311
- assert_equal [authors(:mary)], posts(:authorless).authors
312
- end
313
-
314
- def test_has_many_going_through_join_model_with_custom_primary_key
315
- assert_equal [authors(:david)], posts(:thinking).authors_using_author_id
316
- end
317
-
318
- def test_has_many_going_through_polymorphic_join_model_with_custom_primary_key
319
- assert_equal [tags(:general)], posts(:eager_other).tags_using_author_id
320
- end
321
-
322
- def test_has_many_through_with_custom_primary_key_on_belongs_to_source
323
- assert_equal [authors(:david), authors(:david)], posts(:thinking).author_using_custom_pk
324
- end
325
-
326
- def test_has_many_through_with_custom_primary_key_on_has_many_source
327
- assert_equal [authors(:david), authors(:bob)], posts(:thinking).authors_using_custom_pk.order('authors.id')
328
- end
329
-
330
- def test_both_scoped_and_explicit_joins_should_be_respected
331
- assert_nothing_raised do
332
- Post.send(:with_scope, :find => {:joins => "left outer join comments on comments.id = posts.id"}) do
333
- Post.find :all, :select => "comments.id, authors.id", :joins => "left outer join authors on authors.id = posts.author_id"
334
- end
335
- end
336
- end
337
-
338
- def test_belongs_to_polymorphic_with_counter_cache
339
- assert_equal 1, posts(:welcome)[:taggings_count]
340
- tagging = posts(:welcome).taggings.create(:tag => tags(:general))
341
- assert_equal 2, posts(:welcome, :reload)[:taggings_count]
342
- tagging.destroy
343
- assert_equal 1, posts(:welcome, :reload)[:taggings_count]
344
- end
345
-
346
- def test_unavailable_through_reflection
347
- assert_raise(ActiveRecord::HasManyThroughAssociationNotFoundError) { authors(:david).nothings }
348
- end
349
-
350
- def test_has_many_through_join_model_with_conditions
351
- assert_equal [], posts(:welcome).invalid_taggings
352
- assert_equal [], posts(:welcome).invalid_tags
353
- end
354
-
355
- def test_has_many_polymorphic
356
- assert_raise ActiveRecord::HasManyThroughAssociationPolymorphicSourceError do
357
- tags(:general).taggables
358
- end
359
-
360
- assert_raise ActiveRecord::HasManyThroughAssociationPolymorphicThroughError do
361
- taggings(:welcome_general).things
362
- end
363
-
364
- assert_raise ActiveRecord::EagerLoadPolymorphicError do
365
- tags(:general).taggings.find(:all, :include => :taggable, :conditions => 'bogus_table.column = 1')
366
- end
367
- end
368
-
369
- def test_has_many_polymorphic_with_source_type
370
- # added sort by ID as otherwise Oracle select sometimes returned rows in different order
371
- assert_equal posts(:welcome, :thinking).sort_by(&:id), tags(:general).tagged_posts.sort_by(&:id)
372
- end
373
-
374
- def test_eager_has_many_polymorphic_with_source_type
375
- tag_with_include = Tag.find(tags(:general).id, :include => :tagged_posts)
376
- desired = posts(:welcome, :thinking)
377
- assert_no_queries do
378
- # added sort by ID as otherwise test using JRuby was failing as array elements were in different order
379
- assert_equal desired.sort_by(&:id), tag_with_include.tagged_posts.sort_by(&:id)
380
- end
381
- assert_equal 5, tag_with_include.taggings.length
382
- end
383
-
384
- def test_has_many_through_has_many_find_all
385
- assert_equal comments(:greetings), authors(:david).comments.find(:all, :order => 'comments.id').first
386
- end
387
-
388
- def test_has_many_through_has_many_find_all_with_custom_class
389
- assert_equal comments(:greetings), authors(:david).funky_comments.find(:all, :order => 'comments.id').first
390
- end
391
-
392
- def test_has_many_through_has_many_find_first
393
- assert_equal comments(:greetings), authors(:david).comments.find(:first, :order => 'comments.id')
394
- end
395
-
396
- def test_has_many_through_has_many_find_conditions
397
- options = { :conditions => "comments.#{QUOTED_TYPE}='SpecialComment'", :order => 'comments.id' }
398
- assert_equal comments(:does_it_hurt), authors(:david).comments.find(:first, options)
399
- end
400
-
401
- def test_has_many_through_has_many_find_by_id
402
- assert_equal comments(:more_greetings), authors(:david).comments.find(2)
403
- end
404
-
405
- def test_has_many_through_polymorphic_has_one
406
- assert_equal Tagging.find(1,2).sort_by { |t| t.id }, authors(:david).tagging.order(:id)
407
- end
408
-
409
- def test_has_many_through_polymorphic_has_many
410
- assert_equal taggings(:welcome_general, :thinking_general), authors(:david).taggings.uniq.sort_by { |t| t.id }
411
- end
412
-
413
- def test_include_has_many_through_polymorphic_has_many
414
- author = Author.find_by_id(authors(:david).id, :include => :taggings)
415
- expected_taggings = taggings(:welcome_general, :thinking_general)
416
- assert_no_queries do
417
- assert_equal expected_taggings, author.taggings.uniq.sort_by { |t| t.id }
418
- end
419
- end
420
-
421
- unless current_adapter?(:IBM_DBAdapter)
422
- # DB2 throws SQL0214N
423
- def test_eager_load_has_many_through_has_many
424
- author = Author.find :first, :conditions => ['name = ?', 'David'], :include => :comments, :order => 'comments.id'
425
- SpecialComment.new; VerySpecialComment.new
426
- assert_no_queries do
427
- assert_equal [1,2,3,5,6,7,8,9,10,12], author.comments.collect(&:id)
428
- end
429
- end
430
- end
431
-
432
- def test_eager_load_has_many_through_has_many_with_conditions
433
- post = Post.find(:first, :include => :invalid_tags)
434
- assert_no_queries do
435
- post.invalid_tags
436
- end
437
- end
438
-
439
- def test_eager_belongs_to_and_has_one_not_singularized
440
- assert_nothing_raised do
441
- Author.find(:first, :include => :author_address)
442
- AuthorAddress.find(:first, :include => :author)
443
- end
444
- end
445
-
446
- def test_self_referential_has_many_through
447
- assert_equal [authors(:mary)], authors(:david).favorite_authors
448
- assert_equal [], authors(:mary).favorite_authors
449
- end
450
-
451
- def test_add_to_self_referential_has_many_through
452
- new_author = Author.create(:name => "Bob")
453
- authors(:david).author_favorites.create :favorite_author => new_author
454
- assert_equal new_author, authors(:david).reload.favorite_authors.first
455
- end
456
-
457
- def test_has_many_through_uses_conditions_specified_on_the_has_many_association
458
- author = Author.order(:id).first
459
- assert_present author.comments
460
- assert_blank author.nonexistant_comments
461
- end
462
-
463
- def test_has_many_through_uses_correct_attributes
464
- assert_nil posts(:thinking).tags.find_by_name("General").attributes["tag_id"]
465
- end
466
-
467
- def test_associating_unsaved_records_with_has_many_through
468
- saved_post = posts(:thinking)
469
- new_tag = Tag.new(:name => "new")
470
-
471
- saved_post.tags << new_tag
472
- assert new_tag.persisted? #consistent with habtm!
473
- assert saved_post.persisted?
474
- assert saved_post.tags.include?(new_tag)
475
-
476
- assert new_tag.persisted?
477
- assert new_tag.in?(saved_post.reload.tags(true))
478
-
479
-
480
- new_post = Post.new(:title => "Association replacmenet works!", :body => "You best believe it.")
481
- saved_tag = tags(:general)
482
-
483
- new_post.tags << saved_tag
484
- assert !new_post.persisted?
485
- assert saved_tag.persisted?
486
- assert new_post.tags.include?(saved_tag)
487
-
488
- new_post.save!
489
- assert new_post.persisted?
490
- assert saved_tag.in?(new_post.reload.tags(true))
491
-
492
- assert !posts(:thinking).tags.build.persisted?
493
- assert !posts(:thinking).tags.new.persisted?
494
- end
495
-
496
- def test_create_associate_when_adding_to_has_many_through
497
- count = posts(:thinking).tags.count
498
- push = Tag.create!(:name => 'pushme')
499
- post_thinking = posts(:thinking)
500
- assert_nothing_raised { post_thinking.tags << push }
501
- assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
502
- message = "Expected a Tag in tags collection, got #{wrong.class}.")
503
- assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
504
- message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
505
- assert_equal(count + 1, post_thinking.tags.size)
506
- assert_equal(count + 1, post_thinking.tags(true).size)
507
-
508
- assert_kind_of Tag, post_thinking.tags.create!(:name => 'foo')
509
- assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
510
- message = "Expected a Tag in tags collection, got #{wrong.class}.")
511
- assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
512
- message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
513
- assert_equal(count + 2, post_thinking.tags.size)
514
- assert_equal(count + 2, post_thinking.tags(true).size)
515
-
516
- assert_nothing_raised { post_thinking.tags.concat(Tag.create!(:name => 'abc'), Tag.create!(:name => 'def')) }
517
- assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
518
- message = "Expected a Tag in tags collection, got #{wrong.class}.")
519
- assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
520
- message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
521
- assert_equal(count + 4, post_thinking.tags.size)
522
- assert_equal(count + 4, post_thinking.tags(true).size)
523
-
524
- # Raises if the wrong reflection name is used to set the Edge belongs_to
525
- assert_nothing_raised { vertices(:vertex_1).sinks << vertices(:vertex_5) }
526
- end
527
-
528
- def test_add_to_join_table_with_no_id
529
- assert_nothing_raised { vertices(:vertex_1).sinks << vertices(:vertex_5) }
530
- end
531
-
532
- def test_has_many_through_collection_size_doesnt_load_target_if_not_loaded
533
- author = authors(:david)
534
- assert_equal 10, author.comments.size
535
- assert !author.comments.loaded?
536
- end
537
-
538
- def test_has_many_through_collection_size_uses_counter_cache_if_it_exists
539
- c = categories(:general)
540
- c.categorizations_count = 100
541
- assert_equal 100, c.categorizations.size
542
- assert !c.categorizations.loaded?
543
- end
544
-
545
- def test_adding_junk_to_has_many_through_should_raise_type_mismatch
546
- assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:thinking).tags << "Uhh what now?" }
547
- end
548
-
549
- def test_adding_to_has_many_through_should_return_self
550
- tags = posts(:thinking).tags
551
- assert_equal tags, posts(:thinking).tags.push(tags(:general))
552
- end
553
-
554
- def test_delete_associate_when_deleting_from_has_many_through_with_nonstandard_id
555
- count = books(:awdr).references.count
556
- references_before = books(:awdr).references
557
- book = Book.create!(:name => 'Getting Real')
558
- book_awdr = books(:awdr)
559
- book_awdr.references << book
560
- assert_equal(count + 1, book_awdr.references(true).size)
561
-
562
- assert_nothing_raised { book_awdr.references.delete(book) }
563
- assert_equal(count, book_awdr.references.size)
564
- assert_equal(count, book_awdr.references(true).size)
565
- assert_equal(references_before.sort, book_awdr.references.sort)
566
- end
567
-
568
- def test_delete_associate_when_deleting_from_has_many_through
569
- count = posts(:thinking).tags.count
570
- tags_before = posts(:thinking).tags
571
- tag = Tag.create!(:name => 'doomed')
572
- post_thinking = posts(:thinking)
573
- post_thinking.tags << tag
574
- assert_equal(count + 1, post_thinking.taggings(true).size)
575
- assert_equal(count + 1, post_thinking.tags(true).size)
576
-
577
- assert_nothing_raised { post_thinking.tags.delete(tag) }
578
- assert_equal(count, post_thinking.tags.size)
579
- assert_equal(count, post_thinking.tags(true).size)
580
- assert_equal(count, post_thinking.taggings(true).size)
581
- assert_equal(tags_before.sort, post_thinking.tags.sort)
582
- end
583
-
584
- def test_delete_associate_when_deleting_from_has_many_through_with_multiple_tags
585
- count = posts(:thinking).tags.count
586
- tags_before = posts(:thinking).tags
587
- doomed = Tag.create!(:name => 'doomed')
588
- doomed2 = Tag.create!(:name => 'doomed2')
589
- quaked = Tag.create!(:name => 'quaked')
590
- post_thinking = posts(:thinking)
591
- post_thinking.tags << doomed << doomed2
592
- assert_equal(count + 2, post_thinking.tags(true).size)
593
-
594
- assert_nothing_raised { post_thinking.tags.delete(doomed, doomed2, quaked) }
595
- assert_equal(count, post_thinking.tags.size)
596
- assert_equal(count, post_thinking.tags(true).size)
597
- assert_equal(tags_before.sort, post_thinking.tags.sort)
598
- end
599
-
600
- def test_deleting_junk_from_has_many_through_should_raise_type_mismatch
601
- assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:thinking).tags.delete("Uhh what now?") }
602
- end
603
-
604
- def test_has_many_through_sum_uses_calculations
605
- assert_nothing_raised { authors(:david).comments.sum(:post_id) }
606
- end
607
-
608
- def test_calculations_on_has_many_through_should_disambiguate_fields
609
- assert_nothing_raised { authors(:david).categories.maximum(:id) }
610
- end
611
-
612
- def test_calculations_on_has_many_through_should_not_disambiguate_fields_unless_necessary
613
- assert_nothing_raised { authors(:david).categories.maximum("categories.id") }
614
- end
615
-
616
- def test_has_many_through_has_many_with_sti
617
- assert_equal [comments(:does_it_hurt)], authors(:david).special_post_comments
618
- end
619
-
620
- def test_uniq_has_many_through_should_retain_order
621
- comment_ids = authors(:david).comments.map(&:id)
622
- assert_equal comment_ids.sort, authors(:david).ordered_uniq_comments.map(&:id)
623
- assert_equal comment_ids.sort.reverse, authors(:david).ordered_uniq_comments_desc.map(&:id)
624
- end
625
-
626
- def test_polymorphic_has_many
627
- expected = taggings(:welcome_general)
628
- p = Post.find(posts(:welcome).id, :include => :taggings)
629
- assert_no_queries {assert p.taggings.include?(expected)}
630
- assert posts(:welcome).taggings.include?(taggings(:welcome_general))
631
- end
632
-
633
- def test_polymorphic_has_one
634
- expected = posts(:welcome)
635
-
636
- tagging = Tagging.find(taggings(:welcome_general).id, :include => :taggable)
637
- assert_no_queries { assert_equal expected, tagging.taggable}
638
- end
639
-
640
- def test_polymorphic_belongs_to
641
- p = Post.find(posts(:welcome).id, :include => {:taggings => :taggable})
642
- assert_no_queries {assert_equal posts(:welcome), p.taggings.first.taggable}
643
- end
644
-
645
- def test_preload_polymorphic_has_many_through
646
- posts = Post.find(:all, :order => 'posts.id')
647
- posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
648
- assert_equal posts.length, posts_with_tags.length
649
- posts.length.times do |i|
650
- assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length }
651
- end
652
- end
653
-
654
- def test_preload_polymorph_many_types
655
- taggings = Tagging.find :all, :include => :taggable, :conditions => ['taggable_type != ?', 'FakeModel'], :order => 'id'
656
- assert_no_queries do
657
- taggings.first.taggable.id
658
- taggings[1].taggable.id
659
- end
660
-
661
- taggables = taggings.map(&:taggable)
662
- assert taggables.include?(items(:dvd))
663
- assert taggables.include?(posts(:welcome))
664
- end
665
-
666
- def test_preload_nil_polymorphic_belongs_to
667
- assert_nothing_raised do
668
- Tagging.find(:all, :include => :taggable, :conditions => ['taggable_type IS NULL'])
669
- end
670
- end
671
-
672
- def test_preload_polymorphic_has_many
673
- posts = Post.find(:all, :order => 'posts.id')
674
- posts_with_taggings = Post.find(:all, :include => :taggings, :order => 'posts.id')
675
- assert_equal posts.length, posts_with_taggings.length
676
- posts.length.times do |i|
677
- assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length }
678
- end
679
- end
680
-
681
- def test_belongs_to_shared_parent
682
- comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 1')
683
- assert_no_queries do
684
- assert_equal comments.first.post, comments[1].post
685
- end
686
- end
687
-
688
- def test_has_many_through_include_uses_array_include_after_loaded
689
- david = authors(:david)
690
- david.categories.class # force load target
691
-
692
- category = david.categories.first
693
-
694
- assert_no_queries do
695
- assert david.categories.loaded?
696
- assert david.categories.include?(category)
697
- end
698
- end
699
-
700
- def test_has_many_through_include_checks_if_record_exists_if_target_not_loaded
701
- david = authors(:david)
702
- category = david.categories.first
703
-
704
- david.reload
705
- assert ! david.categories.loaded?
706
- assert_queries(1) do
707
- assert david.categories.include?(category)
708
- end
709
- assert ! david.categories.loaded?
710
- end
711
-
712
- def test_has_many_through_include_returns_false_for_non_matching_record_to_verify_scoping
713
- david = authors(:david)
714
- category = Category.create!(:name => 'Not Associated')
715
-
716
- assert ! david.categories.loaded?
717
- assert ! david.categories.include?(category)
718
- end
719
-
720
- def test_has_many_through_goes_through_all_sti_classes
721
- sub_sti_post = SubStiPost.create!(:title => 'test', :body => 'test', :author_id => 1)
722
- new_comment = sub_sti_post.comments.create(:body => 'test')
723
-
724
- assert_equal [9, 10, new_comment.id], authors(:david).sti_post_comments.map(&:id).sort
725
- end
726
-
727
- def test_has_many_with_pluralize_table_names_false
728
- aircraft = Aircraft.create!(:name => "Airbus 380")
729
- engine = Engine.create!(:car_id => aircraft.id)
730
- assert_equal aircraft.engines, [engine]
731
- end
732
-
733
- private
734
- # create dynamic Post models to allow different dependency options
735
- def find_post_with_dependency(post_id, association, association_name, dependency)
736
- class_name = "PostWith#{association.to_s.classify}#{dependency.to_s.classify}"
737
- Post.find(post_id).update_column :type, class_name
738
- klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
739
- klass.table_name = 'posts'
740
- klass.send(association, association_name, :as => :taggable, :dependent => dependency)
741
- klass.find(post_id)
742
- end
743
- end
1
+ require "cases/helper"
2
+ require 'active_support/core_ext/object/inclusion'
3
+ require 'models/tag'
4
+ require 'models/tagging'
5
+ require 'models/post'
6
+ require 'models/rating'
7
+ require 'models/item'
8
+ require 'models/comment'
9
+ require 'models/author'
10
+ require 'models/category'
11
+ require 'models/categorization'
12
+ require 'models/vertex'
13
+ require 'models/edge'
14
+ require 'models/book'
15
+ require 'models/citation'
16
+ require 'models/aircraft'
17
+ require 'models/engine'
18
+ require 'models/car'
19
+
20
+ class AssociationsJoinModelTest < ActiveRecord::TestCase
21
+ self.use_transactional_fixtures = false unless supports_savepoints?
22
+
23
+ fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books,
24
+ # Reload edges table from fixtures as otherwise repeated test was failing
25
+ :edges
26
+
27
+ def test_has_many
28
+ assert authors(:david).categories.include?(categories(:general))
29
+ end
30
+
31
+ def test_has_many_inherited
32
+ assert authors(:mary).categories.include?(categories(:sti_test))
33
+ end
34
+
35
+ def test_inherited_has_many
36
+ assert categories(:sti_test).authors.include?(authors(:mary))
37
+ end
38
+
39
+ def test_has_many_uniq_through_join_model
40
+ assert_equal 2, authors(:mary).categorized_posts.size
41
+ assert_equal 1, authors(:mary).unique_categorized_posts.size
42
+ end
43
+
44
+ def test_has_many_uniq_through_count
45
+ author = authors(:mary)
46
+ assert !authors(:mary).unique_categorized_posts.loaded?
47
+ assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count }
48
+ assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count(:title) }
49
+ assert_queries(1) { assert_equal 0, author.unique_categorized_posts.count(:title, :conditions => "title is NULL") }
50
+ assert !authors(:mary).unique_categorized_posts.loaded?
51
+ end
52
+
53
+ def test_has_many_uniq_through_find
54
+ assert_equal 1, authors(:mary).unique_categorized_posts.find(:all).size
55
+ end
56
+
57
+ def test_has_many_uniq_through_dynamic_find
58
+ assert_equal 1, authors(:mary).unique_categorized_posts.find_all_by_title("So I was thinking").size
59
+ end
60
+
61
+ def test_polymorphic_has_many_going_through_join_model
62
+ assert_equal tags(:general), tag = posts(:welcome).tags.first
63
+ assert_no_queries do
64
+ tag.tagging
65
+ end
66
+ end
67
+
68
+ def test_count_polymorphic_has_many
69
+ assert_equal 1, posts(:welcome).taggings.count
70
+ assert_equal 1, posts(:welcome).tags.count
71
+ end
72
+
73
+ def test_polymorphic_has_many_going_through_join_model_with_find
74
+ assert_equal tags(:general), tag = posts(:welcome).tags.find(:first)
75
+ assert_no_queries do
76
+ tag.tagging
77
+ end
78
+ end
79
+
80
+ def test_polymorphic_has_many_going_through_join_model_with_include_on_source_reflection
81
+ assert_equal tags(:general), tag = posts(:welcome).funky_tags.first
82
+ assert_no_queries do
83
+ tag.tagging
84
+ end
85
+ end
86
+
87
+ def test_polymorphic_has_many_going_through_join_model_with_include_on_source_reflection_with_find
88
+ assert_equal tags(:general), tag = posts(:welcome).funky_tags.find(:first)
89
+ assert_no_queries do
90
+ tag.tagging
91
+ end
92
+ end
93
+
94
+ def test_polymorphic_has_many_going_through_join_model_with_custom_select_and_joins
95
+ assert_equal tags(:general), tag = posts(:welcome).tags.add_joins_and_select.first
96
+ assert_nothing_raised(NoMethodError) { tag.author_id }
97
+ end
98
+
99
+ def test_polymorphic_has_many_going_through_join_model_with_custom_foreign_key
100
+ assert_equal tags(:misc), taggings(:welcome_general).super_tag
101
+ assert_equal tags(:misc), posts(:welcome).super_tags.first
102
+ end
103
+
104
+ def test_polymorphic_has_many_create_model_with_inheritance_and_custom_base_class
105
+ post = SubStiPost.create :title => 'SubStiPost', :body => 'SubStiPost body'
106
+ assert_instance_of SubStiPost, post
107
+
108
+ tagging = tags(:misc).taggings.create(:taggable => post)
109
+ assert_equal "SubStiPost", tagging.taggable_type
110
+ end
111
+
112
+ def test_polymorphic_has_many_going_through_join_model_with_inheritance
113
+ assert_equal tags(:general), posts(:thinking).tags.first
114
+ end
115
+
116
+ def test_polymorphic_has_many_going_through_join_model_with_inheritance_with_custom_class_name
117
+ assert_equal tags(:general), posts(:thinking).funky_tags.first
118
+ end
119
+
120
+ def test_polymorphic_has_many_create_model_with_inheritance
121
+ post = posts(:thinking)
122
+ assert_instance_of SpecialPost, post
123
+
124
+ tagging = tags(:misc).taggings.create(:taggable => post)
125
+ assert_equal "Post", tagging.taggable_type
126
+ end
127
+
128
+ def test_polymorphic_has_one_create_model_with_inheritance
129
+ tagging = tags(:misc).create_tagging(:taggable => posts(:thinking))
130
+ assert_equal "Post", tagging.taggable_type
131
+ end
132
+
133
+ def test_set_polymorphic_has_many
134
+ tagging = tags(:misc).taggings.create
135
+ posts(:thinking).taggings << tagging
136
+ assert_equal "Post", tagging.taggable_type
137
+ end
138
+
139
+ def test_set_polymorphic_has_one
140
+ tagging = tags(:misc).taggings.create
141
+ posts(:thinking).tagging = tagging
142
+
143
+ assert_equal "Post", tagging.taggable_type
144
+ assert_equal posts(:thinking).id, tagging.taggable_id
145
+ assert_equal posts(:thinking), tagging.taggable
146
+ end
147
+
148
+ def test_set_polymorphic_has_one_on_new_record
149
+ tagging = tags(:misc).taggings.create
150
+ post = Post.new :title => "foo", :body => "bar"
151
+ post.tagging = tagging
152
+ post.save!
153
+
154
+ assert_equal "Post", tagging.taggable_type
155
+ assert_equal post.id, tagging.taggable_id
156
+ assert_equal post, tagging.taggable
157
+ end
158
+
159
+ def test_create_polymorphic_has_many_with_scope
160
+ old_count = posts(:welcome).taggings.count
161
+ tagging = posts(:welcome).taggings.create(:tag => tags(:misc))
162
+ assert_equal "Post", tagging.taggable_type
163
+ assert_equal old_count+1, posts(:welcome).taggings.count
164
+ end
165
+
166
+ def test_create_bang_polymorphic_with_has_many_scope
167
+ old_count = posts(:welcome).taggings.count
168
+ tagging = posts(:welcome).taggings.create!(:tag => tags(:misc))
169
+ assert_equal "Post", tagging.taggable_type
170
+ assert_equal old_count+1, posts(:welcome).taggings.count
171
+ end
172
+
173
+ def test_create_polymorphic_has_one_with_scope
174
+ old_count = Tagging.count
175
+ tagging = posts(:welcome).create_tagging(:tag => tags(:misc))
176
+ assert_equal "Post", tagging.taggable_type
177
+ assert_equal old_count+1, Tagging.count
178
+ end
179
+
180
+ def test_delete_polymorphic_has_many_with_delete_all
181
+ assert_equal 1, posts(:welcome).taggings.count
182
+ posts(:welcome).taggings.first.update_column :taggable_type, 'PostWithHasManyDeleteAll'
183
+ post = find_post_with_dependency(1, :has_many, :taggings, :delete_all)
184
+
185
+ old_count = Tagging.count
186
+ post.destroy
187
+ assert_equal old_count-1, Tagging.count
188
+ assert_equal 0, posts(:welcome).taggings.count
189
+ end
190
+
191
+ def test_delete_polymorphic_has_many_with_destroy
192
+ assert_equal 1, posts(:welcome).taggings.count
193
+ posts(:welcome).taggings.first.update_column :taggable_type, 'PostWithHasManyDestroy'
194
+ post = find_post_with_dependency(1, :has_many, :taggings, :destroy)
195
+
196
+ old_count = Tagging.count
197
+ post.destroy
198
+ assert_equal old_count-1, Tagging.count
199
+ assert_equal 0, posts(:welcome).taggings.count
200
+ end
201
+
202
+ def test_delete_polymorphic_has_many_with_nullify
203
+ assert_equal 1, posts(:welcome).taggings.count
204
+ posts(:welcome).taggings.first.update_column :taggable_type, 'PostWithHasManyNullify'
205
+ post = find_post_with_dependency(1, :has_many, :taggings, :nullify)
206
+
207
+ old_count = Tagging.count
208
+ post.destroy
209
+ assert_equal old_count, Tagging.count
210
+ assert_equal 0, posts(:welcome).taggings.count
211
+ end
212
+
213
+ def test_delete_polymorphic_has_one_with_destroy
214
+ assert posts(:welcome).tagging
215
+ posts(:welcome).tagging.update_column :taggable_type, 'PostWithHasOneDestroy'
216
+ post = find_post_with_dependency(1, :has_one, :tagging, :destroy)
217
+
218
+ old_count = Tagging.count
219
+ post.destroy
220
+ assert_equal old_count-1, Tagging.count
221
+ assert_nil posts(:welcome).tagging(true)
222
+ end
223
+
224
+ def test_delete_polymorphic_has_one_with_nullify
225
+ assert posts(:welcome).tagging
226
+ posts(:welcome).tagging.update_column :taggable_type, 'PostWithHasOneNullify'
227
+ post = find_post_with_dependency(1, :has_one, :tagging, :nullify)
228
+
229
+ old_count = Tagging.count
230
+ post.destroy
231
+ assert_equal old_count, Tagging.count
232
+ assert_nil posts(:welcome).tagging(true)
233
+ end
234
+
235
+ def test_has_many_with_piggyback
236
+ assert_equal "2", categories(:sti_test).authors_with_select.first.post_id.to_s
237
+ end
238
+
239
+ def test_include_has_many_through
240
+ posts = Post.find(:all, :order => 'posts.id')
241
+ posts_with_authors = Post.find(:all, :include => :authors, :order => 'posts.id')
242
+ assert_equal posts.length, posts_with_authors.length
243
+ posts.length.times do |i|
244
+ assert_equal posts[i].authors.length, assert_no_queries { posts_with_authors[i].authors.length }
245
+ end
246
+ end
247
+
248
+ def test_include_polymorphic_has_one
249
+ post = Post.find_by_id(posts(:welcome).id, :include => :tagging)
250
+ tagging = taggings(:welcome_general)
251
+ assert_no_queries do
252
+ assert_equal tagging, post.tagging
253
+ end
254
+ end
255
+
256
+ def test_include_polymorphic_has_one_defined_in_abstract_parent
257
+ item = Item.find_by_id(items(:dvd).id, :include => :tagging)
258
+ tagging = taggings(:godfather)
259
+ assert_no_queries do
260
+ assert_equal tagging, item.tagging
261
+ end
262
+ end
263
+
264
+ def test_include_polymorphic_has_many_through
265
+ posts = Post.find(:all, :order => 'posts.id')
266
+ posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
267
+ assert_equal posts.length, posts_with_tags.length
268
+ posts.length.times do |i|
269
+ assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length }
270
+ end
271
+ end
272
+
273
+ def test_include_polymorphic_has_many
274
+ posts = Post.find(:all, :order => 'posts.id')
275
+ posts_with_taggings = Post.find(:all, :include => :taggings, :order => 'posts.id')
276
+ assert_equal posts.length, posts_with_taggings.length
277
+ posts.length.times do |i|
278
+ assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length }
279
+ end
280
+ end
281
+
282
+ def test_has_many_find_all
283
+ assert_equal [categories(:general)], authors(:david).categories.find(:all)
284
+ end
285
+
286
+ def test_has_many_find_first
287
+ assert_equal categories(:general), authors(:david).categories.find(:first)
288
+ end
289
+
290
+ def test_has_many_with_hash_conditions
291
+ assert_equal categories(:general), authors(:david).categories_like_general.find(:first)
292
+ end
293
+
294
+ def test_has_many_find_conditions
295
+ assert_equal categories(:general), authors(:david).categories.find(:first, :conditions => "categories.name = 'General'")
296
+ assert_nil authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'")
297
+ end
298
+
299
+ def test_has_many_class_methods_called_by_method_missing
300
+ assert_equal categories(:general), authors(:david).categories.find_all_by_name('General').first
301
+ assert_nil authors(:david).categories.find_by_name('Technology')
302
+ end
303
+
304
+ def test_has_many_array_methods_called_by_method_missing
305
+ assert authors(:david).categories.any? { |category| category.name == 'General' }
306
+ assert_nothing_raised { authors(:david).categories.sort }
307
+ end
308
+
309
+ def test_has_many_going_through_join_model_with_custom_foreign_key
310
+ assert_equal [authors(:bob)], posts(:thinking).authors
311
+ assert_equal [authors(:mary)], posts(:authorless).authors
312
+ end
313
+
314
+ def test_has_many_going_through_join_model_with_custom_primary_key
315
+ assert_equal [authors(:david)], posts(:thinking).authors_using_author_id
316
+ end
317
+
318
+ def test_has_many_going_through_polymorphic_join_model_with_custom_primary_key
319
+ assert_equal [tags(:general)], posts(:eager_other).tags_using_author_id
320
+ end
321
+
322
+ def test_has_many_through_with_custom_primary_key_on_belongs_to_source
323
+ assert_equal [authors(:david), authors(:david)], posts(:thinking).author_using_custom_pk
324
+ end
325
+
326
+ def test_has_many_through_with_custom_primary_key_on_has_many_source
327
+ assert_equal [authors(:david), authors(:bob)], posts(:thinking).authors_using_custom_pk.order('authors.id')
328
+ end
329
+
330
+ def test_both_scoped_and_explicit_joins_should_be_respected
331
+ assert_nothing_raised do
332
+ Post.send(:with_scope, :find => {:joins => "left outer join comments on comments.id = posts.id"}) do
333
+ Post.find :all, :select => "comments.id, authors.id", :joins => "left outer join authors on authors.id = posts.author_id"
334
+ end
335
+ end
336
+ end
337
+
338
+ def test_belongs_to_polymorphic_with_counter_cache
339
+ assert_equal 1, posts(:welcome)[:taggings_count]
340
+ tagging = posts(:welcome).taggings.create(:tag => tags(:general))
341
+ assert_equal 2, posts(:welcome, :reload)[:taggings_count]
342
+ tagging.destroy
343
+ assert_equal 1, posts(:welcome, :reload)[:taggings_count]
344
+ end
345
+
346
+ def test_unavailable_through_reflection
347
+ assert_raise(ActiveRecord::HasManyThroughAssociationNotFoundError) { authors(:david).nothings }
348
+ end
349
+
350
+ def test_has_many_through_join_model_with_conditions
351
+ assert_equal [], posts(:welcome).invalid_taggings
352
+ assert_equal [], posts(:welcome).invalid_tags
353
+ end
354
+
355
+ def test_has_many_polymorphic
356
+ assert_raise ActiveRecord::HasManyThroughAssociationPolymorphicSourceError do
357
+ tags(:general).taggables
358
+ end
359
+
360
+ assert_raise ActiveRecord::HasManyThroughAssociationPolymorphicThroughError do
361
+ taggings(:welcome_general).things
362
+ end
363
+
364
+ assert_raise ActiveRecord::EagerLoadPolymorphicError do
365
+ tags(:general).taggings.find(:all, :include => :taggable, :conditions => 'bogus_table.column = 1')
366
+ end
367
+ end
368
+
369
+ def test_has_many_polymorphic_with_source_type
370
+ # added sort by ID as otherwise Oracle select sometimes returned rows in different order
371
+ assert_equal posts(:welcome, :thinking).sort_by(&:id), tags(:general).tagged_posts.sort_by(&:id)
372
+ end
373
+
374
+ def test_eager_has_many_polymorphic_with_source_type
375
+ tag_with_include = Tag.find(tags(:general).id, :include => :tagged_posts)
376
+ desired = posts(:welcome, :thinking)
377
+ assert_no_queries do
378
+ # added sort by ID as otherwise test using JRuby was failing as array elements were in different order
379
+ assert_equal desired.sort_by(&:id), tag_with_include.tagged_posts.sort_by(&:id)
380
+ end
381
+ assert_equal 5, tag_with_include.taggings.length
382
+ end
383
+
384
+ def test_has_many_through_has_many_find_all
385
+ assert_equal comments(:greetings), authors(:david).comments.find(:all, :order => 'comments.id').first
386
+ end
387
+
388
+ def test_has_many_through_has_many_find_all_with_custom_class
389
+ assert_equal comments(:greetings), authors(:david).funky_comments.find(:all, :order => 'comments.id').first
390
+ end
391
+
392
+ def test_has_many_through_has_many_find_first
393
+ assert_equal comments(:greetings), authors(:david).comments.find(:first, :order => 'comments.id')
394
+ end
395
+
396
+ def test_has_many_through_has_many_find_conditions
397
+ options = { :conditions => "comments.#{QUOTED_TYPE}='SpecialComment'", :order => 'comments.id' }
398
+ assert_equal comments(:does_it_hurt), authors(:david).comments.find(:first, options)
399
+ end
400
+
401
+ def test_has_many_through_has_many_find_by_id
402
+ assert_equal comments(:more_greetings), authors(:david).comments.find(2)
403
+ end
404
+
405
+ def test_has_many_through_polymorphic_has_one
406
+ assert_equal Tagging.find(1,2).sort_by { |t| t.id }, authors(:david).tagging.order(:id)
407
+ end
408
+
409
+ def test_has_many_through_polymorphic_has_many
410
+ assert_equal taggings(:welcome_general, :thinking_general), authors(:david).taggings.uniq.sort_by { |t| t.id }
411
+ end
412
+
413
+ def test_include_has_many_through_polymorphic_has_many
414
+ author = Author.find_by_id(authors(:david).id, :include => :taggings)
415
+ expected_taggings = taggings(:welcome_general, :thinking_general)
416
+ assert_no_queries do
417
+ assert_equal expected_taggings, author.taggings.uniq.sort_by { |t| t.id }
418
+ end
419
+ end
420
+
421
+ unless current_adapter?(:IBM_DBAdapter)
422
+ # DB2 throws SQL0214N
423
+ def test_eager_load_has_many_through_has_many
424
+ author = Author.find :first, :conditions => ['name = ?', 'David'], :include => :comments, :order => 'comments.id'
425
+ SpecialComment.new; VerySpecialComment.new
426
+ assert_no_queries do
427
+ assert_equal [1,2,3,5,6,7,8,9,10,12], author.comments.collect(&:id)
428
+ end
429
+ end
430
+ end
431
+
432
+ def test_eager_load_has_many_through_has_many_with_conditions
433
+ post = Post.find(:first, :include => :invalid_tags)
434
+ assert_no_queries do
435
+ post.invalid_tags
436
+ end
437
+ end
438
+
439
+ def test_eager_belongs_to_and_has_one_not_singularized
440
+ assert_nothing_raised do
441
+ Author.find(:first, :include => :author_address)
442
+ AuthorAddress.find(:first, :include => :author)
443
+ end
444
+ end
445
+
446
+ def test_self_referential_has_many_through
447
+ assert_equal [authors(:mary)], authors(:david).favorite_authors
448
+ assert_equal [], authors(:mary).favorite_authors
449
+ end
450
+
451
+ def test_add_to_self_referential_has_many_through
452
+ new_author = Author.create(:name => "Bob")
453
+ authors(:david).author_favorites.create :favorite_author => new_author
454
+ assert_equal new_author, authors(:david).reload.favorite_authors.first
455
+ end
456
+
457
+ def test_has_many_through_uses_conditions_specified_on_the_has_many_association
458
+ author = Author.order(:id).first
459
+ assert_present author.comments
460
+ assert_blank author.nonexistant_comments
461
+ end
462
+
463
+ def test_has_many_through_uses_correct_attributes
464
+ assert_nil posts(:thinking).tags.find_by_name("General").attributes["tag_id"]
465
+ end
466
+
467
+ def test_associating_unsaved_records_with_has_many_through
468
+ saved_post = posts(:thinking)
469
+ new_tag = Tag.new(:name => "new")
470
+
471
+ saved_post.tags << new_tag
472
+ assert new_tag.persisted? #consistent with habtm!
473
+ assert saved_post.persisted?
474
+ assert saved_post.tags.include?(new_tag)
475
+
476
+ assert new_tag.persisted?
477
+ assert new_tag.in?(saved_post.reload.tags(true))
478
+
479
+
480
+ new_post = Post.new(:title => "Association replacmenet works!", :body => "You best believe it.")
481
+ saved_tag = tags(:general)
482
+
483
+ new_post.tags << saved_tag
484
+ assert !new_post.persisted?
485
+ assert saved_tag.persisted?
486
+ assert new_post.tags.include?(saved_tag)
487
+
488
+ new_post.save!
489
+ assert new_post.persisted?
490
+ assert saved_tag.in?(new_post.reload.tags(true))
491
+
492
+ assert !posts(:thinking).tags.build.persisted?
493
+ assert !posts(:thinking).tags.new.persisted?
494
+ end
495
+
496
+ def test_create_associate_when_adding_to_has_many_through
497
+ count = posts(:thinking).tags.count
498
+ push = Tag.create!(:name => 'pushme')
499
+ post_thinking = posts(:thinking)
500
+ assert_nothing_raised { post_thinking.tags << push }
501
+ assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
502
+ message = "Expected a Tag in tags collection, got #{wrong.class}.")
503
+ assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
504
+ message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
505
+ assert_equal(count + 1, post_thinking.tags.size)
506
+ assert_equal(count + 1, post_thinking.tags(true).size)
507
+
508
+ assert_kind_of Tag, post_thinking.tags.create!(:name => 'foo')
509
+ assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
510
+ message = "Expected a Tag in tags collection, got #{wrong.class}.")
511
+ assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
512
+ message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
513
+ assert_equal(count + 2, post_thinking.tags.size)
514
+ assert_equal(count + 2, post_thinking.tags(true).size)
515
+
516
+ assert_nothing_raised { post_thinking.tags.concat(Tag.create!(:name => 'abc'), Tag.create!(:name => 'def')) }
517
+ assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
518
+ message = "Expected a Tag in tags collection, got #{wrong.class}.")
519
+ assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
520
+ message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
521
+ assert_equal(count + 4, post_thinking.tags.size)
522
+ assert_equal(count + 4, post_thinking.tags(true).size)
523
+
524
+ # Raises if the wrong reflection name is used to set the Edge belongs_to
525
+ assert_nothing_raised { vertices(:vertex_1).sinks << vertices(:vertex_5) }
526
+ end
527
+
528
+ def test_add_to_join_table_with_no_id
529
+ assert_nothing_raised { vertices(:vertex_1).sinks << vertices(:vertex_5) }
530
+ end
531
+
532
+ def test_has_many_through_collection_size_doesnt_load_target_if_not_loaded
533
+ author = authors(:david)
534
+ assert_equal 10, author.comments.size
535
+ assert !author.comments.loaded?
536
+ end
537
+
538
+ def test_has_many_through_collection_size_uses_counter_cache_if_it_exists
539
+ c = categories(:general)
540
+ c.categorizations_count = 100
541
+ assert_equal 100, c.categorizations.size
542
+ assert !c.categorizations.loaded?
543
+ end
544
+
545
+ def test_adding_junk_to_has_many_through_should_raise_type_mismatch
546
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:thinking).tags << "Uhh what now?" }
547
+ end
548
+
549
+ def test_adding_to_has_many_through_should_return_self
550
+ tags = posts(:thinking).tags
551
+ assert_equal tags, posts(:thinking).tags.push(tags(:general))
552
+ end
553
+
554
+ def test_delete_associate_when_deleting_from_has_many_through_with_nonstandard_id
555
+ count = books(:awdr).references.count
556
+ references_before = books(:awdr).references
557
+ book = Book.create!(:name => 'Getting Real')
558
+ book_awdr = books(:awdr)
559
+ book_awdr.references << book
560
+ assert_equal(count + 1, book_awdr.references(true).size)
561
+
562
+ assert_nothing_raised { book_awdr.references.delete(book) }
563
+ assert_equal(count, book_awdr.references.size)
564
+ assert_equal(count, book_awdr.references(true).size)
565
+ assert_equal(references_before.sort, book_awdr.references.sort)
566
+ end
567
+
568
+ def test_delete_associate_when_deleting_from_has_many_through
569
+ count = posts(:thinking).tags.count
570
+ tags_before = posts(:thinking).tags
571
+ tag = Tag.create!(:name => 'doomed')
572
+ post_thinking = posts(:thinking)
573
+ post_thinking.tags << tag
574
+ assert_equal(count + 1, post_thinking.taggings(true).size)
575
+ assert_equal(count + 1, post_thinking.tags(true).size)
576
+
577
+ assert_nothing_raised { post_thinking.tags.delete(tag) }
578
+ assert_equal(count, post_thinking.tags.size)
579
+ assert_equal(count, post_thinking.tags(true).size)
580
+ assert_equal(count, post_thinking.taggings(true).size)
581
+ assert_equal(tags_before.sort, post_thinking.tags.sort)
582
+ end
583
+
584
+ def test_delete_associate_when_deleting_from_has_many_through_with_multiple_tags
585
+ count = posts(:thinking).tags.count
586
+ tags_before = posts(:thinking).tags
587
+ doomed = Tag.create!(:name => 'doomed')
588
+ doomed2 = Tag.create!(:name => 'doomed2')
589
+ quaked = Tag.create!(:name => 'quaked')
590
+ post_thinking = posts(:thinking)
591
+ post_thinking.tags << doomed << doomed2
592
+ assert_equal(count + 2, post_thinking.tags(true).size)
593
+
594
+ assert_nothing_raised { post_thinking.tags.delete(doomed, doomed2, quaked) }
595
+ assert_equal(count, post_thinking.tags.size)
596
+ assert_equal(count, post_thinking.tags(true).size)
597
+ assert_equal(tags_before.sort, post_thinking.tags.sort)
598
+ end
599
+
600
+ def test_deleting_junk_from_has_many_through_should_raise_type_mismatch
601
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:thinking).tags.delete("Uhh what now?") }
602
+ end
603
+
604
+ def test_has_many_through_sum_uses_calculations
605
+ assert_nothing_raised { authors(:david).comments.sum(:post_id) }
606
+ end
607
+
608
+ def test_calculations_on_has_many_through_should_disambiguate_fields
609
+ assert_nothing_raised { authors(:david).categories.maximum(:id) }
610
+ end
611
+
612
+ def test_calculations_on_has_many_through_should_not_disambiguate_fields_unless_necessary
613
+ assert_nothing_raised { authors(:david).categories.maximum("categories.id") }
614
+ end
615
+
616
+ def test_has_many_through_has_many_with_sti
617
+ assert_equal [comments(:does_it_hurt)], authors(:david).special_post_comments
618
+ end
619
+
620
+ def test_uniq_has_many_through_should_retain_order
621
+ comment_ids = authors(:david).comments.map(&:id)
622
+ assert_equal comment_ids.sort, authors(:david).ordered_uniq_comments.map(&:id)
623
+ assert_equal comment_ids.sort.reverse, authors(:david).ordered_uniq_comments_desc.map(&:id)
624
+ end
625
+
626
+ def test_polymorphic_has_many
627
+ expected = taggings(:welcome_general)
628
+ p = Post.find(posts(:welcome).id, :include => :taggings)
629
+ assert_no_queries {assert p.taggings.include?(expected)}
630
+ assert posts(:welcome).taggings.include?(taggings(:welcome_general))
631
+ end
632
+
633
+ def test_polymorphic_has_one
634
+ expected = posts(:welcome)
635
+
636
+ tagging = Tagging.find(taggings(:welcome_general).id, :include => :taggable)
637
+ assert_no_queries { assert_equal expected, tagging.taggable}
638
+ end
639
+
640
+ def test_polymorphic_belongs_to
641
+ p = Post.find(posts(:welcome).id, :include => {:taggings => :taggable})
642
+ assert_no_queries {assert_equal posts(:welcome), p.taggings.first.taggable}
643
+ end
644
+
645
+ def test_preload_polymorphic_has_many_through
646
+ posts = Post.find(:all, :order => 'posts.id')
647
+ posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
648
+ assert_equal posts.length, posts_with_tags.length
649
+ posts.length.times do |i|
650
+ assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length }
651
+ end
652
+ end
653
+
654
+ def test_preload_polymorph_many_types
655
+ taggings = Tagging.find :all, :include => :taggable, :conditions => ['taggable_type != ?', 'FakeModel'], :order => 'id'
656
+ assert_no_queries do
657
+ taggings.first.taggable.id
658
+ taggings[1].taggable.id
659
+ end
660
+
661
+ taggables = taggings.map(&:taggable)
662
+ assert taggables.include?(items(:dvd))
663
+ assert taggables.include?(posts(:welcome))
664
+ end
665
+
666
+ def test_preload_nil_polymorphic_belongs_to
667
+ assert_nothing_raised do
668
+ Tagging.find(:all, :include => :taggable, :conditions => ['taggable_type IS NULL'])
669
+ end
670
+ end
671
+
672
+ def test_preload_polymorphic_has_many
673
+ posts = Post.find(:all, :order => 'posts.id')
674
+ posts_with_taggings = Post.find(:all, :include => :taggings, :order => 'posts.id')
675
+ assert_equal posts.length, posts_with_taggings.length
676
+ posts.length.times do |i|
677
+ assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length }
678
+ end
679
+ end
680
+
681
+ def test_belongs_to_shared_parent
682
+ comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 1')
683
+ assert_no_queries do
684
+ assert_equal comments.first.post, comments[1].post
685
+ end
686
+ end
687
+
688
+ def test_has_many_through_include_uses_array_include_after_loaded
689
+ david = authors(:david)
690
+ david.categories.class # force load target
691
+
692
+ category = david.categories.first
693
+
694
+ assert_no_queries do
695
+ assert david.categories.loaded?
696
+ assert david.categories.include?(category)
697
+ end
698
+ end
699
+
700
+ def test_has_many_through_include_checks_if_record_exists_if_target_not_loaded
701
+ david = authors(:david)
702
+ category = david.categories.first
703
+
704
+ david.reload
705
+ assert ! david.categories.loaded?
706
+ assert_queries(1) do
707
+ assert david.categories.include?(category)
708
+ end
709
+ assert ! david.categories.loaded?
710
+ end
711
+
712
+ def test_has_many_through_include_returns_false_for_non_matching_record_to_verify_scoping
713
+ david = authors(:david)
714
+ category = Category.create!(:name => 'Not Associated')
715
+
716
+ assert ! david.categories.loaded?
717
+ assert ! david.categories.include?(category)
718
+ end
719
+
720
+ def test_has_many_through_goes_through_all_sti_classes
721
+ sub_sti_post = SubStiPost.create!(:title => 'test', :body => 'test', :author_id => 1)
722
+ new_comment = sub_sti_post.comments.create(:body => 'test')
723
+
724
+ assert_equal [9, 10, new_comment.id], authors(:david).sti_post_comments.map(&:id).sort
725
+ end
726
+
727
+ def test_has_many_with_pluralize_table_names_false
728
+ aircraft = Aircraft.create!(:name => "Airbus 380")
729
+ engine = Engine.create!(:car_id => aircraft.id)
730
+ assert_equal aircraft.engines, [engine]
731
+ end
732
+
733
+ private
734
+ # create dynamic Post models to allow different dependency options
735
+ def find_post_with_dependency(post_id, association, association_name, dependency)
736
+ class_name = "PostWith#{association.to_s.classify}#{dependency.to_s.classify}"
737
+ Post.find(post_id).update_column :type, class_name
738
+ klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
739
+ klass.table_name = 'posts'
740
+ klass.send(association, association_name, :as => :taggable, :dependent => dependency)
741
+ klass.find(post_id)
742
+ end
743
+ end