join_model_test.rb 26.2 KB
Newer Older
1
require "cases/helper"
J
Jeremy Kemper 已提交
2 3 4 5 6 7 8 9 10 11 12 13
require 'models/tag'
require 'models/tagging'
require 'models/post'
require 'models/item'
require 'models/comment'
require 'models/author'
require 'models/category'
require 'models/categorization'
require 'models/vertex'
require 'models/edge'
require 'models/book'
require 'models/citation'
14

15
class AssociationsJoinModelTest < ActiveRecord::TestCase
16
  self.use_transactional_fixtures = false
17 18 19
  fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books,
    # Reload edges table from fixtures as otherwise repeated test was failing
    :edges
20 21

  def test_has_many
22
    assert authors(:david).categories.include?(categories(:general))
23
  end
24

25
  def test_has_many_inherited
26
    assert authors(:mary).categories.include?(categories(:sti_test))
27
  end
28

29
  def test_inherited_has_many
30 31 32 33 34 35
    assert categories(:sti_test).authors.include?(authors(:mary))
  end

  def test_has_many_uniq_through_join_model
    assert_equal 2, authors(:mary).categorized_posts.size
    assert_equal 1, authors(:mary).unique_categorized_posts.size
36
  end
J
Jeremy Kemper 已提交
37

38 39 40 41 42 43 44 45
  def test_has_many_uniq_through_count
    author = authors(:mary)
    assert !authors(:mary).unique_categorized_posts.loaded?
    assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count }
    assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count(:title) }
    assert_queries(1) { assert_equal 0, author.unique_categorized_posts.count(:title, :conditions => "title is NULL") }
    assert !authors(:mary).unique_categorized_posts.loaded?
  end
46

47 48 49
  def test_has_many_uniq_through_find
    assert_equal 1, authors(:mary).unique_categorized_posts.find(:all).size
  end
50

51 52 53
  def test_has_many_uniq_through_dynamic_find
    assert_equal 1, authors(:mary).unique_categorized_posts.find_all_by_title("So I was thinking").size
  end
J
Jeremy Kemper 已提交
54

55
  def test_polymorphic_has_many_going_through_join_model
56 57 58 59
    assert_equal tags(:general), tag = posts(:welcome).tags.first
    assert_no_queries do
      tag.tagging
    end
60
  end
61

R
Rick Olson 已提交
62 63 64 65 66
  def test_count_polymorphic_has_many
    assert_equal 1, posts(:welcome).taggings.count
    assert_equal 1, posts(:welcome).tags.count
  end

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
  def test_polymorphic_has_many_going_through_join_model_with_find
    assert_equal tags(:general), tag = posts(:welcome).tags.find(:first)
    assert_no_queries do
      tag.tagging
    end
  end

  def test_polymorphic_has_many_going_through_join_model_with_include_on_source_reflection
    assert_equal tags(:general), tag = posts(:welcome).funky_tags.first
    assert_no_queries do
      tag.tagging
    end
  end

  def test_polymorphic_has_many_going_through_join_model_with_include_on_source_reflection_with_find
    assert_equal tags(:general), tag = posts(:welcome).funky_tags.find(:first)
    assert_no_queries do
      tag.tagging
    end
  end

88 89 90 91 92 93 94 95 96 97 98
  def test_polymorphic_has_many_going_through_join_model_with_disabled_include
    assert_equal tags(:general), tag = posts(:welcome).tags.add_joins_and_select.first
    assert_queries 1 do
      tag.tagging
    end
  end

  def test_polymorphic_has_many_going_through_join_model_with_custom_select_and_joins
    assert_equal tags(:general), tag = posts(:welcome).tags.add_joins_and_select.first
    tag.author_id
  end
99

100 101 102 103 104
  def test_polymorphic_has_many_going_through_join_model_with_custom_foreign_key
    assert_equal tags(:misc), taggings(:welcome_general).super_tag
    assert_equal tags(:misc), posts(:welcome).super_tags.first
  end

105 106 107
  def test_polymorphic_has_many_create_model_with_inheritance_and_custom_base_class
    post = SubStiPost.create :title => 'SubStiPost', :body => 'SubStiPost body'
    assert_instance_of SubStiPost, post
J
Jeremy Kemper 已提交
108

109 110 111 112
    tagging = tags(:misc).taggings.create(:taggable => post)
    assert_equal "SubStiPost", tagging.taggable_type
  end

113 114 115
  def test_polymorphic_has_many_going_through_join_model_with_inheritance
    assert_equal tags(:general), posts(:thinking).tags.first
  end
116 117 118 119 120

  def test_polymorphic_has_many_going_through_join_model_with_inheritance_with_custom_class_name
    assert_equal tags(:general), posts(:thinking).funky_tags.first
  end

121 122 123
  def test_polymorphic_has_many_create_model_with_inheritance
    post = posts(:thinking)
    assert_instance_of SpecialPost, post
J
Jeremy Kemper 已提交
124

125 126 127
    tagging = tags(:misc).taggings.create(:taggable => post)
    assert_equal "Post", tagging.taggable_type
  end
128 129 130 131 132 133

  def test_polymorphic_has_one_create_model_with_inheritance
    tagging = tags(:misc).create_tagging(:taggable => posts(:thinking))
    assert_equal "Post", tagging.taggable_type
  end

134 135 136 137 138 139 140 141 142 143 144 145 146
  def test_set_polymorphic_has_many
    tagging = tags(:misc).taggings.create
    posts(:thinking).taggings << tagging
    assert_equal "Post", tagging.taggable_type
  end

  def test_set_polymorphic_has_one
    tagging = tags(:misc).taggings.create
    posts(:thinking).tagging = tagging
    assert_equal "Post", tagging.taggable_type
  end

  def test_create_polymorphic_has_many_with_scope
147 148
    old_count = posts(:welcome).taggings.count
    tagging = posts(:welcome).taggings.create(:tag => tags(:misc))
149
    assert_equal "Post", tagging.taggable_type
150
    assert_equal old_count+1, posts(:welcome).taggings.count
151
  end
J
Jeremy Kemper 已提交
152

153 154 155 156 157 158
  def test_create_bang_polymorphic_with_has_many_scope
    old_count = posts(:welcome).taggings.count
    tagging = posts(:welcome).taggings.create!(:tag => tags(:misc))
    assert_equal "Post", tagging.taggable_type
    assert_equal old_count+1, posts(:welcome).taggings.count
  end
159 160

  def test_create_polymorphic_has_one_with_scope
161 162
    old_count = Tagging.count
    tagging = posts(:welcome).tagging.create(:tag => tags(:misc))
163
    assert_equal "Post", tagging.taggable_type
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
    assert_equal old_count+1, Tagging.count
  end

  def test_delete_polymorphic_has_many_with_delete_all
    assert_equal 1, posts(:welcome).taggings.count
    posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyDeleteAll'
    post = find_post_with_dependency(1, :has_many, :taggings, :delete_all)

    old_count = Tagging.count
    post.destroy
    assert_equal old_count-1, Tagging.count
    assert_equal 0, posts(:welcome).taggings.count
  end

  def test_delete_polymorphic_has_many_with_destroy
    assert_equal 1, posts(:welcome).taggings.count
    posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyDestroy'
    post = find_post_with_dependency(1, :has_many, :taggings, :destroy)

    old_count = Tagging.count
    post.destroy
    assert_equal old_count-1, Tagging.count
    assert_equal 0, posts(:welcome).taggings.count
  end

  def test_delete_polymorphic_has_many_with_nullify
    assert_equal 1, posts(:welcome).taggings.count
    posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyNullify'
    post = find_post_with_dependency(1, :has_many, :taggings, :nullify)

    old_count = Tagging.count
    post.destroy
    assert_equal old_count, Tagging.count
    assert_equal 0, posts(:welcome).taggings.count
  end

  def test_delete_polymorphic_has_one_with_destroy
    assert posts(:welcome).tagging
    posts(:welcome).tagging.update_attribute :taggable_type, 'PostWithHasOneDestroy'
    post = find_post_with_dependency(1, :has_one, :tagging, :destroy)

    old_count = Tagging.count
    post.destroy
    assert_equal old_count-1, Tagging.count
    assert_nil posts(:welcome).tagging(true)
  end

  def test_delete_polymorphic_has_one_with_nullify
    assert posts(:welcome).tagging
    posts(:welcome).tagging.update_attribute :taggable_type, 'PostWithHasOneNullify'
    post = find_post_with_dependency(1, :has_one, :tagging, :nullify)

    old_count = Tagging.count
    post.destroy
    assert_equal old_count, Tagging.count
    assert_nil posts(:welcome).tagging(true)
220 221
  end

222
  def test_has_many_with_piggyback
223
    assert_equal "2", categories(:sti_test).authors.first.post_id.to_s
224
  end
225 226 227 228 229 230 231 232 233 234

  def test_include_has_many_through
    posts              = Post.find(:all, :order => 'posts.id')
    posts_with_authors = Post.find(:all, :include => :authors, :order => 'posts.id')
    assert_equal posts.length, posts_with_authors.length
    posts.length.times do |i|
      assert_equal posts[i].authors.length, assert_no_queries { posts_with_authors[i].authors.length }
    end
  end

235 236 237 238 239 240 241
  def test_include_polymorphic_has_one
    post    = Post.find_by_id(posts(:welcome).id, :include => :tagging)
    tagging = taggings(:welcome_general)
    assert_no_queries do
      assert_equal tagging, post.tagging
    end
  end
J
Jeremy Kemper 已提交
242

243 244 245 246 247 248 249
  def test_include_polymorphic_has_one_defined_in_abstract_parent
    item    = Item.find_by_id(items(:dvd).id, :include => :tagging)
    tagging = taggings(:godfather)
    assert_no_queries do
      assert_equal tagging, item.tagging
    end
  end
J
Jeremy Kemper 已提交
250

251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
  def test_include_polymorphic_has_many_through
    posts           = Post.find(:all, :order => 'posts.id')
    posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
    assert_equal posts.length, posts_with_tags.length
    posts.length.times do |i|
      assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length }
    end
  end

  def test_include_polymorphic_has_many
    posts               = Post.find(:all, :order => 'posts.id')
    posts_with_taggings = Post.find(:all, :include => :taggings, :order => 'posts.id')
    assert_equal posts.length, posts_with_taggings.length
    posts.length.times do |i|
      assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length }
    end
  end

269 270 271
  def test_has_many_find_all
    assert_equal [categories(:general)], authors(:david).categories.find(:all)
  end
J
Jeremy Kemper 已提交
272

273 274 275
  def test_has_many_find_first
    assert_equal categories(:general), authors(:david).categories.find(:first)
  end
276 277 278 279

  def test_has_many_with_hash_conditions
    assert_equal categories(:general), authors(:david).categories_like_general.find(:first)
  end
J
Jeremy Kemper 已提交
280

281 282
  def test_has_many_find_conditions
    assert_equal categories(:general), authors(:david).categories.find(:first, :conditions => "categories.name = 'General'")
283
    assert_nil authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'")
284
  end
285

286
  def test_has_many_class_methods_called_by_method_missing
287
    assert_equal categories(:general), authors(:david).categories.find_all_by_name('General').first
288
    assert_nil authors(:david).categories.find_by_name('Technology')
289
  end
290

291
  def test_has_many_array_methods_called_by_method_missing
292
    assert authors(:david).categories.any? { |category| category.name == 'General' }
293 294 295
    assert_nothing_raised { authors(:david).categories.sort }
  end

296 297 298 299
  def test_has_many_going_through_join_model_with_custom_foreign_key
    assert_equal [], posts(:thinking).authors
    assert_equal [authors(:mary)], posts(:authorless).authors
  end
300

301 302 303 304 305 306 307
  def test_both_scoped_and_explicit_joins_should_be_respected
    assert_nothing_raised do
      Post.send(:with_scope, :find => {:joins => "left outer join comments on comments.id = posts.id"}) do
        Post.find :all, :select => "comments.id, authors.id", :joins => "left outer join authors on authors.id = posts.author_id"
      end
    end
  end
308 309

  def test_belongs_to_polymorphic_with_counter_cache
310
    assert_equal 1, posts(:welcome)[:taggings_count]
311
    tagging = posts(:welcome).taggings.create(:tag => tags(:general))
312
    assert_equal 2, posts(:welcome, :reload)[:taggings_count]
313
    tagging.destroy
314
    assert_equal 1, posts(:welcome, :reload)[:taggings_count]
315
  end
316

317
  def test_unavailable_through_reflection
318
    assert_raise(ActiveRecord::HasManyThroughAssociationNotFoundError) { authors(:david).nothings }
319 320
  end

321 322 323 324 325
  def test_has_many_through_join_model_with_conditions
    assert_equal [], posts(:welcome).invalid_taggings
    assert_equal [], posts(:welcome).invalid_tags
  end

326
  def test_has_many_polymorphic
327
    assert_raise ActiveRecord::HasManyThroughAssociationPolymorphicError do
328
      assert_equal posts(:welcome, :thinking), tags(:general).taggables
329
    end
330
    assert_raise ActiveRecord::EagerLoadPolymorphicError do
331
      assert_equal posts(:welcome, :thinking), tags(:general).taggings.find(:all, :include => :taggable, :conditions => 'bogus_table.column = 1')
332 333
    end
  end
J
Jeremy Kemper 已提交
334

335
  def test_has_many_polymorphic_with_source_type
336 337
    # added sort by ID as otherwise Oracle select sometimes returned rows in different order
    assert_equal posts(:welcome, :thinking).sort_by(&:id), tags(:general).tagged_posts.sort_by(&:id)
338 339 340 341
  end

  def test_eager_has_many_polymorphic_with_source_type
    tag_with_include = Tag.find(tags(:general).id, :include => :tagged_posts)
342
    desired = posts(:welcome, :thinking)
343
    assert_no_queries do
344 345
      # added sort by ID as otherwise test using JRuby was failing as array elements were in different order
      assert_equal desired.sort_by(&:id), tag_with_include.tagged_posts.sort_by(&:id)
346
    end
347
    assert_equal 5, tag_with_include.taggings.length
348
  end
349

350
  def test_has_many_through_has_many_find_all
351
    assert_equal comments(:greetings), authors(:david).comments.find(:all, :order => 'comments.id').first
352 353
  end

354 355 356 357
  def test_has_many_through_has_many_find_all_with_custom_class
    assert_equal comments(:greetings), authors(:david).funky_comments.find(:all, :order => 'comments.id').first
  end

358
  def test_has_many_through_has_many_find_first
359
    assert_equal comments(:greetings), authors(:david).comments.find(:first, :order => 'comments.id')
360 361 362
  end

  def test_has_many_through_has_many_find_conditions
363 364
    options = { :conditions => "comments.#{QUOTED_TYPE}='SpecialComment'", :order => 'comments.id' }
    assert_equal comments(:does_it_hurt), authors(:david).comments.find(:first, options)
365 366 367 368 369 370
  end

  def test_has_many_through_has_many_find_by_id
    assert_equal comments(:more_greetings), authors(:david).comments.find(2)
  end

371
  def test_has_many_through_polymorphic_has_one
372
    assert_equal Tagging.find(1,2).sort_by { |t| t.id }, authors(:david).tagging
373 374 375
  end

  def test_has_many_through_polymorphic_has_many
376
    assert_equal taggings(:welcome_general, :thinking_general), authors(:david).taggings.uniq.sort_by { |t| t.id }
377 378
  end

379
  def test_include_has_many_through_polymorphic_has_many
380
    author            = Author.find_by_id(authors(:david).id, :include => :taggings)
381
    expected_taggings = taggings(:welcome_general, :thinking_general)
382 383 384 385 386
    assert_no_queries do
      assert_equal expected_taggings, author.taggings.uniq.sort_by { |t| t.id }
    end
  end

387 388 389 390 391 392 393 394
  def test_has_many_through_has_many_through
    assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).tags }
  end

  def test_has_many_through_habtm
    assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).post_categories }
  end

395 396 397 398
  def test_eager_load_has_many_through_has_many
    author = Author.find :first, :conditions => ['name = ?', 'David'], :include => :comments, :order => 'comments.id'
    SpecialComment.new; VerySpecialComment.new
    assert_no_queries do
399
      assert_equal [1,2,3,5,6,7,8,9,10,12], author.comments.collect(&:id)
400 401
    end
  end
J
Jeremy Kemper 已提交
402

403 404 405 406 407 408
  def test_eager_load_has_many_through_has_many_with_conditions
    post = Post.find(:first, :include => :invalid_tags)
    assert_no_queries do
      post.invalid_tags
    end
  end
409

410 411 412 413 414 415 416
  def test_eager_belongs_to_and_has_one_not_singularized
    assert_nothing_raised do
      Author.find(:first, :include => :author_address)
      AuthorAddress.find(:first, :include => :author)
    end
  end

417 418 419 420 421 422 423 424
  def test_self_referential_has_many_through
    assert_equal [authors(:mary)], authors(:david).favorite_authors
    assert_equal [],               authors(:mary).favorite_authors
  end

  def test_add_to_self_referential_has_many_through
    new_author = Author.create(:name => "Bob")
    authors(:david).author_favorites.create :favorite_author => new_author
R
Rick Olson 已提交
425
    assert_equal new_author, authors(:david).reload.favorite_authors.first
426
  end
J
Jeremy Kemper 已提交
427

428 429
  def test_has_many_through_uses_conditions_specified_on_the_has_many_association
    author = Author.find(:first)
430 431
    assert_present author.comments
    assert_blank author.nonexistant_comments
432
  end
433

434 435 436 437
  def test_has_many_through_uses_correct_attributes
    assert_nil posts(:thinking).tags.find_by_name("General").attributes["tag_id"]
  end

438 439 440 441 442
  def test_associating_unsaved_records_with_has_many_through
    saved_post = posts(:thinking)
    new_tag = Tag.new(:name => "new")

    saved_post.tags << new_tag
443 444
    assert new_tag.persisted? #consistent with habtm!
    assert saved_post.persisted?
445 446
    assert saved_post.tags.include?(new_tag)

447
    assert new_tag.persisted?
448 449 450 451 452 453 454
    assert saved_post.reload.tags(true).include?(new_tag)


    new_post = Post.new(:title => "Association replacmenet works!", :body => "You best believe it.")
    saved_tag = tags(:general)

    new_post.tags << saved_tag
455 456
    assert !new_post.persisted?
    assert saved_tag.persisted?
457 458 459
    assert new_post.tags.include?(saved_tag)

    new_post.save!
460
    assert new_post.persisted?
461 462
    assert new_post.reload.tags(true).include?(saved_tag)

463 464
    assert !posts(:thinking).tags.build.persisted?
    assert !posts(:thinking).tags.new.persisted?
465
  end
466 467

  def test_create_associate_when_adding_to_has_many_through
468 469
    count = posts(:thinking).tags.count
    push = Tag.create!(:name => 'pushme')
470 471 472 473 474 475 476 477 478
    post_thinking = posts(:thinking)
    assert_nothing_raised { post_thinking.tags << push }
    assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
                message = "Expected a Tag in tags collection, got #{wrong.class}.")
    assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
                message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
    assert_equal(count + 1, post_thinking.tags.size)
    assert_equal(count + 1, post_thinking.tags(true).size)

479
    assert_kind_of Tag, post_thinking.tags.create!(:name => 'foo')
480 481 482 483 484 485 486 487 488 489 490 491 492 493
    assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
                message = "Expected a Tag in tags collection, got #{wrong.class}.")
    assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
                message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
    assert_equal(count + 2, post_thinking.tags.size)
    assert_equal(count + 2, post_thinking.tags(true).size)

    assert_nothing_raised { post_thinking.tags.concat(Tag.create!(:name => 'abc'), Tag.create!(:name => 'def')) }
    assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
                message = "Expected a Tag in tags collection, got #{wrong.class}.")
    assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
                message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
    assert_equal(count + 4, post_thinking.tags.size)
    assert_equal(count + 4, post_thinking.tags(true).size)
494 495 496

    # Raises if the wrong reflection name is used to set the Edge belongs_to
    assert_nothing_raised { vertices(:vertex_1).sinks << vertices(:vertex_5) }
497 498
  end

499 500
  def test_has_many_through_collection_size_doesnt_load_target_if_not_loaded
    author = authors(:david)
501
    assert_equal 10, author.comments.size
502 503 504
    assert !author.comments.loaded?
  end

505 506 507 508 509
  def test_has_many_through_collection_size_uses_counter_cache_if_it_exists
    author = authors(:david)
    author.stubs(:read_attribute).with('comments_count').returns(100)
    assert_equal 100, author.comments.size
    assert !author.comments.loaded?
510 511
  end

512 513 514 515 516 517 518 519 520
  def test_adding_junk_to_has_many_through_should_raise_type_mismatch
    assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:thinking).tags << "Uhh what now?" }
  end

  def test_adding_to_has_many_through_should_return_self
    tags = posts(:thinking).tags
    assert_equal tags, posts(:thinking).tags.push(tags(:general))
  end

521 522 523 524 525 526 527 528 529 530 531 532 533 534
  def test_delete_associate_when_deleting_from_has_many_through_with_nonstandard_id
    count = books(:awdr).references.count
    references_before = books(:awdr).references
    book = Book.create!(:name => 'Getting Real')
    book_awdr = books(:awdr)
    book_awdr.references << book
    assert_equal(count + 1, book_awdr.references(true).size)

    assert_nothing_raised { book_awdr.references.delete(book) }
    assert_equal(count, book_awdr.references.size)
    assert_equal(count, book_awdr.references(true).size)
    assert_equal(references_before.sort, book_awdr.references.sort)
  end

535 536 537 538 539 540
  def test_delete_associate_when_deleting_from_has_many_through
    count = posts(:thinking).tags.count
    tags_before = posts(:thinking).tags
    tag = Tag.create!(:name => 'doomed')
    post_thinking = posts(:thinking)
    post_thinking.tags << tag
541
    assert_equal(count + 1, post_thinking.taggings(true).size)
542 543
    assert_equal(count + 1, post_thinking.tags(true).size)

J
Jeremy Kemper 已提交
544
    assert_nothing_raised { post_thinking.tags.delete(tag) }
545 546
    assert_equal(count, post_thinking.tags.size)
    assert_equal(count, post_thinking.tags(true).size)
547
    assert_equal(count, post_thinking.taggings(true).size)
548 549 550 551 552 553 554 555 556 557 558 559 560
    assert_equal(tags_before.sort, post_thinking.tags.sort)
  end

  def test_delete_associate_when_deleting_from_has_many_through_with_multiple_tags
    count = posts(:thinking).tags.count
    tags_before = posts(:thinking).tags
    doomed = Tag.create!(:name => 'doomed')
    doomed2 = Tag.create!(:name => 'doomed2')
    quaked = Tag.create!(:name => 'quaked')
    post_thinking = posts(:thinking)
    post_thinking.tags << doomed << doomed2
    assert_equal(count + 2, post_thinking.tags(true).size)

J
Jeremy Kemper 已提交
561
    assert_nothing_raised { post_thinking.tags.delete(doomed, doomed2, quaked) }
562 563 564 565 566 567 568 569
    assert_equal(count, post_thinking.tags.size)
    assert_equal(count, post_thinking.tags(true).size)
    assert_equal(tags_before.sort, post_thinking.tags.sort)
  end

  def test_deleting_junk_from_has_many_through_should_raise_type_mismatch
    assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:thinking).tags.delete("Uhh what now?") }
  end
570

571 572 573
  def test_has_many_through_sum_uses_calculations
    assert_nothing_raised { authors(:david).comments.sum(:post_id) }
  end
574

575 576 577
  def test_calculations_on_has_many_through_should_disambiguate_fields
    assert_nothing_raised { authors(:david).categories.maximum(:id) }
  end
578

579 580 581 582
  def test_calculations_on_has_many_through_should_not_disambiguate_fields_unless_necessary
    assert_nothing_raised { authors(:david).categories.maximum("categories.id") }
  end

583 584 585
  def test_has_many_through_has_many_with_sti
    assert_equal [comments(:does_it_hurt)], authors(:david).special_post_comments
  end
J
Jeremy Kemper 已提交
586

587 588 589 590 591
  def test_uniq_has_many_through_should_retain_order
    comment_ids = authors(:david).comments.map(&:id)
    assert_equal comment_ids.sort, authors(:david).ordered_uniq_comments.map(&:id)
    assert_equal comment_ids.sort.reverse, authors(:david).ordered_uniq_comments_desc.map(&:id)
  end
592

593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
  def test_polymorphic_has_many
    expected = taggings(:welcome_general)
    p = Post.find(posts(:welcome).id, :include => :taggings)
    assert_no_queries {assert p.taggings.include?(expected)}
    assert posts(:welcome).taggings.include?(taggings(:welcome_general))
  end

  def test_polymorphic_has_one
    expected = posts(:welcome)

    tagging  = Tagging.find(taggings(:welcome_general).id, :include => :taggable)
    assert_no_queries { assert_equal expected, tagging.taggable}
  end

  def test_polymorphic_belongs_to
    p = Post.find(posts(:welcome).id, :include => {:taggings => :taggable})
    assert_no_queries {assert_equal posts(:welcome), p.taggings.first.taggable}
  end

  def test_preload_polymorphic_has_many_through
    posts           = Post.find(:all, :order => 'posts.id')
    posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
    assert_equal posts.length, posts_with_tags.length
    posts.length.times do |i|
      assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length }
    end
  end

  def test_preload_polymorph_many_types
    taggings = Tagging.find :all, :include => :taggable, :conditions => ['taggable_type != ?', 'FakeModel']
    assert_no_queries do
      taggings.first.taggable.id
      taggings[1].taggable.id
    end

    taggables = taggings.map(&:taggable)
    assert taggables.include?(items(:dvd))
    assert taggables.include?(posts(:welcome))
  end

633 634
  def test_preload_nil_polymorphic_belongs_to
    assert_nothing_raised do
A
Aaron Patterson 已提交
635
      Tagging.find(:all, :include => :taggable, :conditions => ['taggable_type IS NULL'])
636 637 638
    end
  end

639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
  def test_preload_polymorphic_has_many
    posts               = Post.find(:all, :order => 'posts.id')
    posts_with_taggings = Post.find(:all, :include => :taggings, :order => 'posts.id')
    assert_equal posts.length, posts_with_taggings.length
    posts.length.times do |i|
      assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length }
    end
  end

  def test_belongs_to_shared_parent
    comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 1')
    assert_no_queries do
      assert_equal comments.first.post, comments[1].post
    end
  end
654 655 656

  def test_has_many_through_include_uses_array_include_after_loaded
    david = authors(:david)
657 658
    david.categories.class # force load target

659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
    category = david.categories.first

    assert_no_queries do
      assert david.categories.loaded?
      assert david.categories.include?(category)
    end
  end

  def test_has_many_through_include_checks_if_record_exists_if_target_not_loaded
    david = authors(:david)
    category = david.categories.first

    david.reload
    assert ! david.categories.loaded?
    assert_queries(1) do
      assert david.categories.include?(category)
    end
    assert ! david.categories.loaded?
  end
678

679 680 681 682 683 684 685 686
  def test_has_many_through_include_returns_false_for_non_matching_record_to_verify_scoping
    david = authors(:david)
    category = Category.create!(:name => 'Not Associated')

    assert ! david.categories.loaded?
    assert ! david.categories.include?(category)
  end

687 688 689 690 691 692 693
  def test_has_many_through_goes_through_all_sti_classes
    sub_sti_post = SubStiPost.create!(:title => 'test', :body => 'test', :author_id => 1)
    new_comment = sub_sti_post.comments.create(:body => 'test')

    assert_equal [9, 10, new_comment.id], authors(:david).sti_post_comments.map(&:id).sort
  end

694 695 696 697 698 699 700 701 702 703
  private
    # create dynamic Post models to allow different dependency options
    def find_post_with_dependency(post_id, association, association_name, dependency)
      class_name = "PostWith#{association.to_s.classify}#{dependency.to_s.classify}"
      Post.find(post_id).update_attribute :type, class_name
      klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
      klass.set_table_name 'posts'
      klass.send(association, association_name, :as => :taggable, :dependent => dependency)
      klass.find(post_id)
    end
704
end