join_model_test.rb 27.0 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 308 309 310 311 312 313 314 315 316
  def test_has_many_going_through_join_model_with_custom_primary_key
    assert_equal [authors(:david)], posts(:thinking).authors_using_author_id
  end

  def test_has_many_going_through_polymorphic_join_model_with_custom_primary_key
    assert_equal [tags(:general)], posts(:eager_other).tags_using_author_id
  end

  def test_has_many_through_with_custom_primary_key_on_belongs_to_source
    assert_equal [authors(:david), authors(:david)], posts(:thinking).author_using_custom_pk
  end

  def test_has_many_through_with_custom_primary_key_on_has_many_source
    assert_equal [authors(:david)], posts(:thinking).authors_using_custom_pk
  end

317 318 319 320 321 322 323
  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
324 325

  def test_belongs_to_polymorphic_with_counter_cache
326
    assert_equal 1, posts(:welcome)[:taggings_count]
327
    tagging = posts(:welcome).taggings.create(:tag => tags(:general))
328
    assert_equal 2, posts(:welcome, :reload)[:taggings_count]
329
    tagging.destroy
330
    assert_equal 1, posts(:welcome, :reload)[:taggings_count]
331
  end
332

333
  def test_unavailable_through_reflection
334
    assert_raise(ActiveRecord::HasManyThroughAssociationNotFoundError) { authors(:david).nothings }
335 336
  end

337 338 339 340 341
  def test_has_many_through_join_model_with_conditions
    assert_equal [], posts(:welcome).invalid_taggings
    assert_equal [], posts(:welcome).invalid_tags
  end

342
  def test_has_many_polymorphic
343
    assert_raise ActiveRecord::HasManyThroughAssociationPolymorphicError do
344
      assert_equal posts(:welcome, :thinking), tags(:general).taggables
345
    end
346
    assert_raise ActiveRecord::EagerLoadPolymorphicError do
347
      assert_equal posts(:welcome, :thinking), tags(:general).taggings.find(:all, :include => :taggable, :conditions => 'bogus_table.column = 1')
348 349
    end
  end
J
Jeremy Kemper 已提交
350

351
  def test_has_many_polymorphic_with_source_type
352 353
    # 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)
354 355 356 357
  end

  def test_eager_has_many_polymorphic_with_source_type
    tag_with_include = Tag.find(tags(:general).id, :include => :tagged_posts)
358
    desired = posts(:welcome, :thinking)
359
    assert_no_queries do
360 361
      # 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)
362
    end
363
    assert_equal 5, tag_with_include.taggings.length
364
  end
365

366
  def test_has_many_through_has_many_find_all
367
    assert_equal comments(:greetings), authors(:david).comments.find(:all, :order => 'comments.id').first
368 369
  end

370 371 372 373
  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

374
  def test_has_many_through_has_many_find_first
375
    assert_equal comments(:greetings), authors(:david).comments.find(:first, :order => 'comments.id')
376 377 378
  end

  def test_has_many_through_has_many_find_conditions
379 380
    options = { :conditions => "comments.#{QUOTED_TYPE}='SpecialComment'", :order => 'comments.id' }
    assert_equal comments(:does_it_hurt), authors(:david).comments.find(:first, options)
381 382 383 384 385 386
  end

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

387
  def test_has_many_through_polymorphic_has_one
388
    assert_equal Tagging.find(1,2).sort_by { |t| t.id }, authors(:david).tagging
389 390 391
  end

  def test_has_many_through_polymorphic_has_many
392
    assert_equal taggings(:welcome_general, :thinking_general), authors(:david).taggings.uniq.sort_by { |t| t.id }
393 394
  end

395
  def test_include_has_many_through_polymorphic_has_many
396
    author            = Author.find_by_id(authors(:david).id, :include => :taggings)
397
    expected_taggings = taggings(:welcome_general, :thinking_general)
398 399 400 401 402
    assert_no_queries do
      assert_equal expected_taggings, author.taggings.uniq.sort_by { |t| t.id }
    end
  end

403 404 405 406 407 408 409 410
  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

411 412 413 414
  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
415
      assert_equal [1,2,3,5,6,7,8,9,10,12], author.comments.collect(&:id)
416 417
    end
  end
J
Jeremy Kemper 已提交
418

419 420 421 422 423 424
  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
425

426 427 428 429 430 431 432
  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

433 434 435 436 437 438 439 440
  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 已提交
441
    assert_equal new_author, authors(:david).reload.favorite_authors.first
442
  end
J
Jeremy Kemper 已提交
443

444 445
  def test_has_many_through_uses_conditions_specified_on_the_has_many_association
    author = Author.find(:first)
446 447
    assert_present author.comments
    assert_blank author.nonexistant_comments
448
  end
449

450 451 452 453
  def test_has_many_through_uses_correct_attributes
    assert_nil posts(:thinking).tags.find_by_name("General").attributes["tag_id"]
  end

454 455 456 457 458
  def test_associating_unsaved_records_with_has_many_through
    saved_post = posts(:thinking)
    new_tag = Tag.new(:name => "new")

    saved_post.tags << new_tag
459 460
    assert new_tag.persisted? #consistent with habtm!
    assert saved_post.persisted?
461 462
    assert saved_post.tags.include?(new_tag)

463
    assert new_tag.persisted?
464 465 466 467 468 469 470
    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
471 472
    assert !new_post.persisted?
    assert saved_tag.persisted?
473 474 475
    assert new_post.tags.include?(saved_tag)

    new_post.save!
476
    assert new_post.persisted?
477 478
    assert new_post.reload.tags(true).include?(saved_tag)

479 480
    assert !posts(:thinking).tags.build.persisted?
    assert !posts(:thinking).tags.new.persisted?
481
  end
482 483

  def test_create_associate_when_adding_to_has_many_through
484 485
    count = posts(:thinking).tags.count
    push = Tag.create!(:name => 'pushme')
486 487 488 489 490 491 492 493 494
    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)

495
    assert_kind_of Tag, post_thinking.tags.create!(:name => 'foo')
496 497 498 499 500 501 502 503 504 505 506 507 508 509
    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)
510 511 512

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

515 516 517 518
  def test_add_to_join_table_with_no_id
    assert_nothing_raised { vertices(:vertex_1).sinks << vertices(:vertex_5) }
  end

519 520
  def test_has_many_through_collection_size_doesnt_load_target_if_not_loaded
    author = authors(:david)
521
    assert_equal 10, author.comments.size
522 523 524
    assert !author.comments.loaded?
  end

525 526 527 528 529
  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?
530 531
  end

532 533 534 535 536 537 538 539 540
  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

541 542 543 544 545 546 547 548 549 550 551 552 553 554
  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

555 556 557 558 559 560
  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
561
    assert_equal(count + 1, post_thinking.taggings(true).size)
562 563
    assert_equal(count + 1, post_thinking.tags(true).size)

J
Jeremy Kemper 已提交
564
    assert_nothing_raised { post_thinking.tags.delete(tag) }
565 566
    assert_equal(count, post_thinking.tags.size)
    assert_equal(count, post_thinking.tags(true).size)
567
    assert_equal(count, post_thinking.taggings(true).size)
568 569 570 571 572 573 574 575 576 577 578 579 580
    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 已提交
581
    assert_nothing_raised { post_thinking.tags.delete(doomed, doomed2, quaked) }
582 583 584 585 586 587 588 589
    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
590

591 592 593
  def test_has_many_through_sum_uses_calculations
    assert_nothing_raised { authors(:david).comments.sum(:post_id) }
  end
594

595 596 597
  def test_calculations_on_has_many_through_should_disambiguate_fields
    assert_nothing_raised { authors(:david).categories.maximum(:id) }
  end
598

599 600 601 602
  def test_calculations_on_has_many_through_should_not_disambiguate_fields_unless_necessary
    assert_nothing_raised { authors(:david).categories.maximum("categories.id") }
  end

603 604 605
  def test_has_many_through_has_many_with_sti
    assert_equal [comments(:does_it_hurt)], authors(:david).special_post_comments
  end
J
Jeremy Kemper 已提交
606

607 608 609 610 611
  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
612

613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
  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

653 654
  def test_preload_nil_polymorphic_belongs_to
    assert_nothing_raised do
A
Aaron Patterson 已提交
655
      Tagging.find(:all, :include => :taggable, :conditions => ['taggable_type IS NULL'])
656 657 658
    end
  end

659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
  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
674 675 676

  def test_has_many_through_include_uses_array_include_after_loaded
    david = authors(:david)
677 678
    david.categories.class # force load target

679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
    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
698

699 700 701 702 703 704 705 706
  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

707 708 709 710 711 712 713
  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

714 715 716 717 718 719 720 721 722 723
  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
724
end