join_model_test.rb 25.7 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
  fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books
18 19

  def test_has_many
20
    assert authors(:david).categories.include?(categories(:general))
21
  end
22

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

27
  def test_inherited_has_many
28 29 30 31 32 33
    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
34
  end
J
Jeremy Kemper 已提交
35

36 37 38 39 40 41 42 43
  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
44 45 46 47 48 49 50 51
  
  def test_has_many_uniq_through_find
    assert_equal 1, authors(:mary).unique_categorized_posts.find(:all).size
  end
  
  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 已提交
52

53
  def test_polymorphic_has_many
54
    assert posts(:welcome).taggings.include?(taggings(:welcome_general))
55
  end
56

57 58 59
  def test_polymorphic_has_one
    assert_equal taggings(:welcome_general), posts(:welcome).tagging
  end
60

61
  def test_polymorphic_belongs_to
62 63
    assert_equal posts(:welcome), posts(:welcome).taggings.first.taggable
  end
64 65

  def test_polymorphic_has_many_going_through_join_model
66 67 68 69
    assert_equal tags(:general), tag = posts(:welcome).tags.first
    assert_no_queries do
      tag.tagging
    end
70
  end
71

R
Rick Olson 已提交
72 73 74 75 76
  def test_count_polymorphic_has_many
    assert_equal 1, posts(:welcome).taggings.count
    assert_equal 1, posts(:welcome).tags.count
  end

77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
  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

98 99 100 101 102 103 104 105 106 107 108
  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
109

110 111 112 113 114
  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

115 116 117
  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 已提交
118

119 120 121 122
    tagging = tags(:misc).taggings.create(:taggable => post)
    assert_equal "SubStiPost", tagging.taggable_type
  end

123 124 125
  def test_polymorphic_has_many_going_through_join_model_with_inheritance
    assert_equal tags(:general), posts(:thinking).tags.first
  end
126 127 128 129 130

  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

131 132 133
  def test_polymorphic_has_many_create_model_with_inheritance
    post = posts(:thinking)
    assert_instance_of SpecialPost, post
J
Jeremy Kemper 已提交
134

135 136 137
    tagging = tags(:misc).taggings.create(:taggable => post)
    assert_equal "Post", tagging.taggable_type
  end
138 139 140 141 142 143

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

144 145 146 147 148 149 150 151 152 153 154 155 156
  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
157 158
    old_count = posts(:welcome).taggings.count
    tagging = posts(:welcome).taggings.create(:tag => tags(:misc))
159
    assert_equal "Post", tagging.taggable_type
160
    assert_equal old_count+1, posts(:welcome).taggings.count
161
  end
J
Jeremy Kemper 已提交
162

163 164 165 166 167 168
  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
169 170

  def test_create_polymorphic_has_one_with_scope
171 172
    old_count = Tagging.count
    tagging = posts(:welcome).tagging.create(:tag => tags(:misc))
173
    assert_equal "Post", tagging.taggable_type
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 220 221 222 223 224 225 226 227 228 229
    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)
230 231
  end

232
  def test_has_many_with_piggyback
233
    assert_equal "2", categories(:sti_test).authors.first.post_id.to_s
234
  end
235 236 237 238 239 240 241 242 243 244

  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

245 246 247 248 249 250 251
  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 已提交
252

253 254 255 256 257 258 259
  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 已提交
260

261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
  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

279 280 281
  def test_has_many_find_all
    assert_equal [categories(:general)], authors(:david).categories.find(:all)
  end
J
Jeremy Kemper 已提交
282

283 284 285
  def test_has_many_find_first
    assert_equal categories(:general), authors(:david).categories.find(:first)
  end
286 287 288 289

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

291 292 293 294
  def test_has_many_find_conditions
    assert_equal categories(:general), authors(:david).categories.find(:first, :conditions => "categories.name = 'General'")
    assert_equal nil, authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'")
  end
295

296
  def test_has_many_class_methods_called_by_method_missing
297
    assert_equal categories(:general), authors(:david).categories.find_all_by_name('General').first
298
    assert_equal nil, authors(:david).categories.find_by_name('Technology')
299
  end
300

301 302 303 304 305
  def test_has_many_array_methods_called_by_method_missing
    assert true, authors(:david).categories.any? { |category| category.name == 'General' }
    assert_nothing_raised { authors(:david).categories.sort }
  end

306 307 308 309
  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
310 311 312 313 314 315 316 317
  
  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
318 319 320 321 322 323 324 325

  def test_belongs_to_polymorphic_with_counter_cache
    assert_equal 0, posts(:welcome)[:taggings_count]
    tagging = posts(:welcome).taggings.create(:tag => tags(:general))
    assert_equal 1, posts(:welcome, :reload)[:taggings_count]
    tagging.destroy
    assert posts(:welcome, :reload)[:taggings_count].zero?
  end
326

327
  def test_unavailable_through_reflection
328
    assert_raise(ActiveRecord::HasManyThroughAssociationNotFoundError) { authors(:david).nothings }
329 330
  end

331 332 333 334 335
  def test_has_many_through_join_model_with_conditions
    assert_equal [], posts(:welcome).invalid_taggings
    assert_equal [], posts(:welcome).invalid_tags
  end

336
  def test_has_many_polymorphic
337
    assert_raise ActiveRecord::HasManyThroughAssociationPolymorphicError do
338
      assert_equal posts(:welcome, :thinking), tags(:general).taggables
339
    end
340
    assert_raise ActiveRecord::EagerLoadPolymorphicError do
341
      assert_equal posts(:welcome, :thinking), tags(:general).taggings.find(:all, :include => :taggable, :conditions => 'bogus_table.column = 1')
342 343
    end
  end
J
Jeremy Kemper 已提交
344

345
  def test_has_many_polymorphic_with_source_type
346
    assert_equal posts(:welcome, :thinking), tags(:general).tagged_posts
347 348 349 350
  end

  def test_eager_has_many_polymorphic_with_source_type
    tag_with_include = Tag.find(tags(:general).id, :include => :tagged_posts)
351
    desired = posts(:welcome, :thinking)
352 353 354
    assert_no_queries do
      assert_equal desired, tag_with_include.tagged_posts
    end
355
    assert_equal 5, tag_with_include.taggings.length
356
  end
357

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

362 363 364 365
  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

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

  def test_has_many_through_has_many_find_conditions
371 372
    options = { :conditions => "comments.#{QUOTED_TYPE}='SpecialComment'", :order => 'comments.id' }
    assert_equal comments(:does_it_hurt), authors(:david).comments.find(:first, options)
373 374 375 376 377 378
  end

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

379 380 381 382 383
  def test_has_many_through_polymorphic_has_one
    assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).tagging }
  end

  def test_has_many_through_polymorphic_has_many
384
    assert_equal taggings(:welcome_general, :thinking_general), authors(:david).taggings.uniq.sort_by { |t| t.id }
385 386
  end

387
  def test_include_has_many_through_polymorphic_has_many
388
    author            = Author.find_by_id(authors(:david).id, :include => :taggings)
389
    expected_taggings = taggings(:welcome_general, :thinking_general)
390 391 392 393 394
    assert_no_queries do
      assert_equal expected_taggings, author.taggings.uniq.sort_by { |t| t.id }
    end
  end

395 396 397 398 399 400 401 402
  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

403 404 405 406 407 408 409
  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
      assert_equal [1,2,3,5,6,7,8,9,10], author.comments.collect(&:id)
    end
  end
J
Jeremy Kemper 已提交
410

411 412 413 414 415 416
  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
417

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

425 426 427 428 429 430 431 432
  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 已提交
433
    assert_equal new_author, authors(:david).reload.favorite_authors.first
434
  end
J
Jeremy Kemper 已提交
435

436 437 438 439 440
  def test_has_many_through_uses_conditions_specified_on_the_has_many_association
    author = Author.find(:first)
    assert !author.comments.blank?
    assert author.nonexistant_comments.blank?
  end
441

442 443 444 445
  def test_has_many_through_uses_correct_attributes
    assert_nil posts(:thinking).tags.find_by_name("General").attributes["tag_id"]
  end

446 447 448 449
  def test_raise_error_when_adding_new_record_to_has_many_through
    assert_raise(ActiveRecord::HasManyThroughCantAssociateNewRecords) { posts(:thinking).tags << tags(:general).clone }
    assert_raise(ActiveRecord::HasManyThroughCantAssociateNewRecords) { posts(:thinking).clone.tags << tags(:general) }
    assert_raise(ActiveRecord::HasManyThroughCantAssociateNewRecords) { posts(:thinking).tags.build }
450
    assert_raise(ActiveRecord::HasManyThroughCantAssociateNewRecords) { posts(:thinking).tags.new }
451
  end
452 453

  def test_create_associate_when_adding_to_has_many_through
454 455
    count = posts(:thinking).tags.count
    push = Tag.create!(:name => 'pushme')
456 457 458 459 460 461 462 463 464
    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)

465
    assert_kind_of Tag, post_thinking.tags.create!(:name => 'foo')
466 467 468 469 470 471 472 473 474 475 476 477 478 479
    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)
480 481 482

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

485 486 487 488 489 490
  def test_has_many_through_collection_size_doesnt_load_target_if_not_loaded
    author = authors(:david)
    assert_equal 9, author.comments.size
    assert !author.comments.loaded?
  end

491 492 493 494 495 496 497 498 499
  uses_mocha('has_many_through_collection_size_uses_counter_cache_if_it_exists') do
    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?
    end
  end

500 501 502 503 504 505 506 507 508
  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

509 510 511 512 513 514 515 516 517 518 519 520 521 522
  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

523 524 525 526 527 528
  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
529
    assert_equal(count + 1, post_thinking.taggings(true).size)
530 531
    assert_equal(count + 1, post_thinking.tags(true).size)

J
Jeremy Kemper 已提交
532
    assert_nothing_raised { post_thinking.tags.delete(tag) }
533 534
    assert_equal(count, post_thinking.tags.size)
    assert_equal(count, post_thinking.tags(true).size)
535
    assert_equal(count, post_thinking.taggings(true).size)
536 537 538 539 540 541 542 543 544 545 546 547 548
    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 已提交
549
    assert_nothing_raised { post_thinking.tags.delete(doomed, doomed2, quaked) }
550 551 552 553 554 555 556 557
    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
558

559 560 561
  def test_has_many_through_sum_uses_calculations
    assert_nothing_raised { authors(:david).comments.sum(:post_id) }
  end
562

563 564 565 566 567 568 569 570
  def test_calculations_on_has_many_through_should_disambiguate_fields
    assert_nothing_raised { authors(:david).categories.maximum(:id) }
  end
  
  def test_calculations_on_has_many_through_should_not_disambiguate_fields_unless_necessary
    assert_nothing_raised { authors(:david).categories.maximum("categories.id") }
  end

571 572 573
  def test_has_many_through_has_many_with_sti
    assert_equal [comments(:does_it_hurt)], authors(:david).special_post_comments
  end
J
Jeremy Kemper 已提交
574

575 576 577 578 579
  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
580

581 582 583 584 585 586 587 588 589 590 591 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
  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

621 622 623 624 625 626
  def test_preload_nil_polymorphic_belongs_to
    assert_nothing_raised do
      taggings = Tagging.find(:all, :include => :taggable, :conditions => ['taggable_type IS NULL'])
    end
  end

627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
  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
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663

  def test_has_many_through_include_uses_array_include_after_loaded
    david = authors(:david)
    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
664
  
665 666 667 668 669 670 671 672
  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

673 674 675 676 677 678 679 680 681 682
  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
683
end