class HasManyThroughAssociationsTest

Public Class Methods

name() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 71
def self.name; "Person"; end

Public Instance Methods

setup() click to toggle source

Dummies to force column loads so query counts are clean.

# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 44
def setup
  Person.create first_name: "gummy"
  Reader.create person_id: 0, post_id: 0
end
test_add_two_instance_and_then_deleting() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 244
def test_add_two_instance_and_then_deleting
  post   = posts(:thinking)
  person = people(:david)

  post.people << person
  post.people << person

  counts = ["post.people.count", "post.people.to_a.count", "post.readers.count", "post.readers.to_a.count"]
  assert_difference counts, -2 do
    post.people.delete(person)
  end

  assert_not_includes post.people.reload, person
end
test_assign_array_to_new_record_builds_join_records() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1061
def test_assign_array_to_new_record_builds_join_records
  c = Category.new(name: "Fishing", authors: [Author.first])
  assert_equal 1, c.categorizations.size
end
test_associate_existing() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 168
def test_associate_existing
  post   = posts(:thinking)
  person = people(:david)

  assert_queries(1) do
    post.people << person
  end

  assert_queries(1) do
    assert_includes post.people, person
  end

  assert_includes post.reload.people.reload, person
end
test_associate_existing_record_twice_should_add_records_twice() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 234
def test_associate_existing_record_twice_should_add_records_twice
  post   = posts(:thinking)
  person = people(:david)

  assert_difference "post.people.count", 2 do
    post.people << person
    post.people << person
  end
end
test_associate_existing_record_twice_should_add_to_target_twice() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 224
def test_associate_existing_record_twice_should_add_to_target_twice
  post   = posts(:thinking)
  person = people(:david)

  assert_difference "post.people.to_a.count", 2 do
    post.people << person
    post.people << person
  end
end
test_associate_existing_with_nonstandard_primary_key_on_belongs_to() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 823
def test_associate_existing_with_nonstandard_primary_key_on_belongs_to
  Categorization.create(author: authors(:mary), named_category_name: categories(:general).name)
  assert_equal categories(:general), authors(:mary).named_categories.first
end
test_associate_new_by_building() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 280
def test_associate_new_by_building
  assert_queries(1) { posts(:thinking) }

  assert_queries(0) do
    posts(:thinking).people.build(first_name: "Bob")
    posts(:thinking).people.new(first_name: "Ted")
  end

  # Should only need to load the association once
  assert_queries(1) do
    assert_includes posts(:thinking).people.collect(&:first_name), "Bob"
    assert_includes posts(:thinking).people.collect(&:first_name), "Ted"
  end

  # 2 queries for each new record (1 to save the record itself, 1 for the join model)
  #    * 2 new records = 4
  # + 1 query to save the actual post = 5
  assert_queries(5) do
    posts(:thinking).body += "-changed"
    posts(:thinking).save
  end

  assert_includes posts(:thinking).reload.people.reload.collect(&:first_name), "Bob"
  assert_includes posts(:thinking).reload.people.reload.collect(&:first_name), "Ted"
end
test_associate_with_create() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 581
def test_associate_with_create
  assert_queries(1) { posts(:thinking) }

  # 1 query for the new record, 1 for the join table record
  # No need to update the actual collection yet!
  assert_queries(2) do
    posts(:thinking).people.create(first_name: "Jeb")
  end

  # *Now* we actually need the collection so it's loaded
  assert_queries(1) do
    assert_includes posts(:thinking).people.collect(&:first_name), "Jeb"
  end

  assert_includes posts(:thinking).reload.people.reload.collect(&:first_name), "Jeb"
end
test_associate_with_create_and_invalid_options() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 632
def test_associate_with_create_and_invalid_options
  firm = companies(:first_firm)
  assert_no_difference("firm.developers.count") { assert_nothing_raised { firm.developers.create(name: "0") } }
end
test_associate_with_create_and_no_options() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 604
def test_associate_with_create_and_no_options
  peeps = posts(:thinking).people.count
  posts(:thinking).people.create(first_name: "foo")
  assert_equal peeps + 1, posts(:thinking).people.count
end
test_associate_with_create_and_valid_options() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 637
def test_associate_with_create_and_valid_options
  firm = companies(:first_firm)
  assert_difference("firm.developers.count", 1) { firm.developers.create(name: "developer") }
end
test_associate_with_create_bang_and_invalid_options() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 642
def test_associate_with_create_bang_and_invalid_options
  firm = companies(:first_firm)
  assert_no_difference("firm.developers.count") { assert_raises(ActiveRecord::RecordInvalid) { firm.developers.create!(name: "0") } }
end
test_associate_with_create_bang_and_valid_options() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 647
def test_associate_with_create_bang_and_valid_options
  firm = companies(:first_firm)
  assert_difference("firm.developers.count", 1) { firm.developers.create!(name: "developer") }
end
test_associate_with_create_exclamation_and_no_options() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 616
def test_associate_with_create_exclamation_and_no_options
  peeps = posts(:thinking).people.count
  posts(:thinking).people.create!(first_name: "foo")
  assert_equal peeps + 1, posts(:thinking).people.count
end
test_associate_with_create_with_through_having_conditions() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 610
def test_associate_with_create_with_through_having_conditions
  impatient_people = posts(:thinking).impatient_people.count
  posts(:thinking).impatient_people.create!(first_name: "foo")
  assert_equal impatient_people + 1, posts(:thinking).impatient_people.count
end
test_associating_new() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 259
def test_associating_new
  assert_queries(1) { posts(:thinking) }
  new_person = nil # so block binding catches it

  assert_queries(0) do
    new_person = Person.new first_name: "bob"
  end

  # Associating new records always saves them
  # Thus, 1 query for the new person record, 1 query for the new join table record
  assert_queries(2) do
    posts(:thinking).people << new_person
  end

  assert_queries(1) do
    assert_includes posts(:thinking).people, new_person
  end

  assert_includes posts(:thinking).reload.people.reload, new_person
end
test_association_callback_ordering() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 684
def test_association_callback_ordering
  Post.reset_log
  log = Post.log
  post = posts(:thinking)

  post.people_with_callbacks << people(:michael)
  assert_equal [
    [:added, :before, "Michael"],
    [:added, :after, "Michael"]
  ], log.last(2)

  post.people_with_callbacks.push(people(:david), Person.create!(first_name: "Bob"), Person.new(first_name: "Lary"))
  assert_equal [
    [:added, :before, "David"],
    [:added, :after, "David"],
    [:added, :before, "Bob"],
    [:added, :after, "Bob"],
    [:added, :before, "Lary"],
    [:added, :after, "Lary"]
  ], log.last(6)

  post.people_with_callbacks.build(first_name: "Ted")
  assert_equal [
    [:added, :before, "Ted"],
    [:added, :after, "Ted"]
  ], log.last(2)

  post.people_with_callbacks.create(first_name: "Sam")
  assert_equal [
    [:added, :before, "Sam"],
    [:added, :after, "Sam"]
  ], log.last(2)

  post.people_with_callbacks = [people(:michael), people(:david), Person.new(first_name: "Julian"), Person.create!(first_name: "Roger")]
  assert_equal((%w(Ted Bob Sam Lary) * 2).sort, log[-12..-5].collect(&:last).sort)
  assert_equal [
    [:added, :before, "Julian"],
    [:added, :after, "Julian"],
    [:added, :before, "Roger"],
    [:added, :after, "Roger"]
  ], log.last(4)
end
test_association_proxy_transaction_method_starts_transaction_in_association_class() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 768
def test_association_proxy_transaction_method_starts_transaction_in_association_class
  assert_called(Tag, :transaction) do
    Post.first.tags.transaction do
      # nothing
    end
  end
end
test_attributes_are_being_set_when_initialized_from_hm_through_association_with_multiple_where_clauses() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 908
def test_attributes_are_being_set_when_initialized_from_hm_through_association_with_multiple_where_clauses
  new_subscriber = books(:awdr).subscribers.where(nick: "marklazz").where(name: "Marcelo Giorgi").build
  assert_equal new_subscriber.nick, "marklazz"
  assert_equal new_subscriber.name, "Marcelo Giorgi"
end
test_attributes_are_being_set_when_initialized_from_hm_through_association_with_where_clause() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 903
def test_attributes_are_being_set_when_initialized_from_hm_through_association_with_where_clause
  new_subscriber = books(:awdr).subscribers.where(nick: "marklazz").build
  assert_equal new_subscriber.nick, "marklazz"
end
test_belongs_to_with_dependent_delete_all() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 463
def test_belongs_to_with_dependent_delete_all
  person = PersonWithDependentDeleteAllJobs.find(1)

  # Create a reference which is not linked to a job. This should not be destroyed.
  person.references.create!

  assert_no_difference "Job.count" do
    assert_difference "Reference.count", -person.jobs.count do
      person.destroy
    end
  end
end
test_belongs_to_with_dependent_destroy() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 450
def test_belongs_to_with_dependent_destroy
  person = PersonWithDependentDestroyJobs.find(1)

  # Create a reference which is not linked to a job. This should not be destroyed.
  person.references.create!

  assert_no_difference "Job.count" do
    assert_difference "Reference.count", -person.jobs.count do
      person.destroy
    end
  end
end
test_belongs_to_with_dependent_nullify() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 476
def test_belongs_to_with_dependent_nullify
  person = PersonWithDependentNullifyJobs.find(1)

  references = person.references.to_a

  assert_no_difference ["Reference.count", "Job.count"] do
    person.destroy
  end

  references.each do |reference|
    assert_nil reference.reload.job_id
  end
end
test_both_parent_ids_set_when_saving_new() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 335
def test_both_parent_ids_set_when_saving_new
  post = Post.new(title: "Hello", body: "world")
  person = Person.new(first_name: "Sean")

  post.people = [person]
  post.save

  assert post.id
  assert person.id
  assert_equal post.id, post.readers.first.post_id
  assert_equal person.id, post.readers.first.person_id
end
test_build_a_model_from_hm_through_association_with_where_clause() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 899
def test_build_a_model_from_hm_through_association_with_where_clause
  assert_nothing_raised { books(:awdr).subscribers.where(nick: "marklazz").build }
end
test_build_for_has_many_through_association() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1210
def test_build_for_has_many_through_association
  organization = organizations(:nsa)
  author = organization.author
  post_direct = author.posts.build
  post_through = organization.posts.build
  assert_equal post_direct.author_id, post_through.author_id
end
test_build_then_remove_then_save() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 324
def test_build_then_remove_then_save
  post = posts(:thinking)
  post.people.build(first_name: "Bob")
  ted = post.people.build(first_name: "Ted")
  post.people.delete(ted)
  post.save!
  post.reload

  assert_equal ["Bob"], post.people.collect(&:first_name)
end
test_build_then_save_with_has_many_inverse() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 306
def test_build_then_save_with_has_many_inverse
  post   = posts(:thinking)
  person = post.people.build(first_name: "Bob")
  person.save
  post.reload

  assert_includes post.people, person
end
test_build_then_save_with_has_one_inverse() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 315
def test_build_then_save_with_has_one_inverse
  post   = posts(:thinking)
  person = post.single_people.build(first_name: "Bob")
  person.save
  post.reload

  assert_includes post.single_people, person
end
test_can_update_through_association() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 933
def test_can_update_through_association
  assert_nothing_raised do
    people(:michael).posts.first.update!(title: "Can write")
  end
end
test_clear_associations() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 670
def test_clear_associations
  assert_queries(2) { posts(:welcome);posts(:welcome).people.reload }

  assert_queries(1) do
    posts(:welcome).people.clear
  end

  assert_queries(0) do
    assert posts(:welcome).people.empty?
  end

  assert posts(:welcome).reload.people.reload.empty?
end
test_collection_build_with_nonstandard_primary_key_on_belongs_to() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 828
def test_collection_build_with_nonstandard_primary_key_on_belongs_to
  author   = authors(:mary)
  category = author.named_categories.build(name: "Primary")
  author.save
  assert Categorization.exists?(author_id: author.id, named_category_name: category.name)
  assert_includes author.named_categories.reload, category
end
test_collection_create_with_nonstandard_primary_key_on_belongs_to() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 836
def test_collection_create_with_nonstandard_primary_key_on_belongs_to
  author   = authors(:mary)
  category = author.named_categories.create(name: "Primary")
  assert Categorization.exists?(author_id: author.id, named_category_name: category.name)
  assert_includes author.named_categories.reload, category
end
test_collection_delete_with_nonstandard_primary_key_on_belongs_to() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 850
def test_collection_delete_with_nonstandard_primary_key_on_belongs_to
  author   = authors(:mary)
  category = author.named_categories.create(name: "Primary")
  author.named_categories.delete(category)
  assert !Categorization.exists?(author_id: author.id, named_category_name: category.name)
  assert author.named_categories.reload.empty?
end
test_collection_exists() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 843
def test_collection_exists
  author   = authors(:mary)
  category = Category.create!(author_ids: [author.id], name: "Primary")
  assert category.authors.exists?(id: author.id)
  assert category.reload.authors.exists?(id: author.id)
end
test_collection_singular_ids_getter_with_string_primary_keys() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 858
def test_collection_singular_ids_getter_with_string_primary_keys
  book = books(:awdr)
  assert_equal 2, book.subscriber_ids.size
  assert_equal [subscribers(:first).nick, subscribers(:second).nick].sort, book.subscriber_ids.sort
end
test_collection_singular_ids_setter() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 864
def test_collection_singular_ids_setter
  company = companies(:quails_core)
  dev = Developer.first

  company.developer_ids = [dev.id]
  assert_equal [dev], company.developers
end
test_collection_singular_ids_setter_raises_exception_when_invalid_ids_set() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 883
def test_collection_singular_ids_setter_raises_exception_when_invalid_ids_set
  company = companies(:quails_core)
  ids = [Developer.first.id, -9999]
  e = assert_raises(ActiveRecord::RecordNotFound) { company.developer_ids = ids }
  msg = "Couldn't find all Developers with 'id': (1, -9999) (found 1 results, but was looking for 2). Couldn't find Developer with id -9999."
  assert_equal(msg, e.message)
end
test_collection_singular_ids_setter_with_string_primary_keys() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 872
def test_collection_singular_ids_setter_with_string_primary_keys
  assert_nothing_raised do
    book = books(:awdr)
    book.subscriber_ids = [subscribers(:second).nick]
    assert_equal [subscribers(:second)], book.subscribers.reload

    book.subscriber_ids = []
    assert_equal [], book.subscribers.reload
  end
end
test_collection_singular_ids_through_setter_raises_exception_when_invalid_ids_set() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 891
def test_collection_singular_ids_through_setter_raises_exception_when_invalid_ids_set
  author = authors(:david)
  ids = [categories(:general).name, "Unknown"]
  e = assert_raises(ActiveRecord::RecordNotFound) { author.essay_category_ids = ids }
  msg = "Couldn't find all Categories with 'name': (General, Unknown) (found 1 results, but was looking for 2). Couldn't find Category with name Unknown."
  assert_equal msg, e.message
end
test_concat() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 216
def test_concat
  person = people(:david)
  post   = posts(:thinking)
  post.people.concat [person]
  assert_equal 1, post.people.size
  assert_equal 1, post.people.reload.size
end
test_count_has_many_through_with_named_scope() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1008
def test_count_has_many_through_with_named_scope
  assert_equal 2, authors(:mary).categories.count
  assert_equal 1, authors(:mary).categories.general.count
end
test_count_with_include_should_alias_join_table() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 733
def test_count_with_include_should_alias_join_table
  assert_equal 2, people(:michael).posts.includes(:readers).count
end
test_create_bang_should_raise_exception_when_join_record_has_errors() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1066
def test_create_bang_should_raise_exception_when_join_record_has_errors
  repair_validations(Categorization) do
    Categorization.validate { |r| r.errors[:base] << "Invalid Categorization" }
    assert_raises(ActiveRecord::RecordInvalid) do
      Category.create!(name: "Fishing", authors: [Author.first])
    end
  end
end
test_create_has_many_through_with_default_scope_on_join_model() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 976
def test_create_has_many_through_with_default_scope_on_join_model
  category = authors(:david).special_categories.create(name: "Foo")
  assert_equal 1, category.categorizations.where(special: true).count
end
test_create_on_new_record() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 622
def test_create_on_new_record
  p = Post.new

  error = assert_raises(ActiveRecord::RecordNotSaved) { p.people.create(first_name: "mew") }
  assert_equal "You cannot call create unless the parent is saved", error.message

  error = assert_raises(ActiveRecord::RecordNotSaved) { p.people.create!(first_name: "snow") }
  assert_equal "You cannot call create unless the parent is saved", error.message
end
test_create_should_not_raise_exception_when_join_record_has_errors() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1054
def test_create_should_not_raise_exception_when_join_record_has_errors
  repair_validations(Categorization) do
    Categorization.validate { |r| r.errors[:base] << "Invalid Categorization" }
    Category.create(name: "Fishing", authors: [Author.first])
  end
end
test_create_with_conditions_hash_on_through_association() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1028
def test_create_with_conditions_hash_on_through_association
  member = members(:groucho)
  club   = member.clubs.create!

  assert_equal true, club.reload.membership.favourite
end
test_delete_all_for_with_dependent_option_delete_all() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 205
def test_delete_all_for_with_dependent_option_delete_all
  person = people(:david)
  assert_equal 1, person.jobs_with_dependent_delete_all.count

  assert_no_difference "Job.count" do
    assert_difference "Reference.count", -1 do
      person.reload.jobs_with_dependent_delete_all.delete_all
    end
  end
end
test_delete_all_for_with_dependent_option_destroy() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 183
def test_delete_all_for_with_dependent_option_destroy
  person = people(:david)
  assert_equal 1, person.jobs_with_dependent_destroy.count

  assert_no_difference "Job.count" do
    assert_difference "Reference.count", -1 do
      person.reload.jobs_with_dependent_destroy.delete_all
    end
  end
end
test_delete_all_for_with_dependent_option_nullify() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 194
def test_delete_all_for_with_dependent_option_nullify
  person = people(:david)
  assert_equal 1, person.jobs_with_dependent_nullify.count

  assert_no_difference "Job.count" do
    assert_no_difference "Reference.count" do
      person.reload.jobs_with_dependent_nullify.delete_all
    end
  end
end
test_delete_association() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 348
def test_delete_association
  assert_queries(2) { posts(:welcome);people(:michael); }

  assert_queries(1) do
    posts(:welcome).people.delete(people(:michael))
  end

  assert_queries(1) do
    assert posts(:welcome).people.empty?
  end

  assert posts(:welcome).reload.people.reload.empty?
end
test_delete_through_belongs_to_with_dependent_delete_all() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 408
def test_delete_through_belongs_to_with_dependent_delete_all
  Reference.make_comments = true

  person = people(:michael)
  job    = jobs(:magician)

  # Make sure we're not deleting everything
  assert person.jobs.count >= 2

  assert_no_difference "Job.count" do
    assert_difference ["person.jobs.count", "Reference.count"], -1 do
      person.jobs_with_dependent_delete_all.delete(job)
    end
  end

  # Check that the destroy callback on Reference did not run
  assert_nil person.reload.comments
ensure
  Reference.make_comments = false
end
test_delete_through_belongs_to_with_dependent_destroy() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 429
def test_delete_through_belongs_to_with_dependent_destroy
  Reference.make_comments = true

  person = people(:michael)
  job    = jobs(:magician)

  # Make sure we're not deleting everything
  assert person.jobs.count >= 2

  assert_no_difference "Job.count" do
    assert_difference ["person.jobs.count", "Reference.count"], -1 do
      person.jobs_with_dependent_destroy.delete(job)
    end
  end

  # Check that the destroy callback on Reference ran
  assert_equal "Reference destroyed", person.reload.comments
ensure
  Reference.make_comments = false
end
test_delete_through_belongs_to_with_dependent_nullify() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 390
def test_delete_through_belongs_to_with_dependent_nullify
  Reference.make_comments = true

  person    = people(:michael)
  job       = jobs(:magician)
  reference = Reference.where(job_id: job.id, person_id: person.id).first

  assert_no_difference ["Job.count", "Reference.count"] do
    assert_difference "person.jobs.count", -1 do
      person.jobs_with_dependent_nullify.delete(job)
    end
  end

  assert_nil reference.reload.job_id
ensure
  Reference.make_comments = false
end
test_deleting_from_has_many_through_a_belongs_to_should_not_try_to_update_counter() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1035
def test_deleting_from_has_many_through_a_belongs_to_should_not_try_to_update_counter
  post    = posts(:welcome)
  address = author_addresses(:david_address)

  assert_includes post.author_addresses, address
  post.author_addresses.delete(address)
  assert post[:author_count].nil?
end
test_destroy_all() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 373
def test_destroy_all
  assert_no_difference "Person.count" do
    assert_difference "Reader.count", -1 do
      posts(:welcome).people.destroy_all
    end
  end

  assert posts(:welcome).reload.people.empty?
  assert posts(:welcome).people.reload.empty?
end
test_destroy_association() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 362
def test_destroy_association
  assert_no_difference "Person.count" do
    assert_difference "Reader.count", -1 do
      posts(:welcome).people.destroy(people(:michael))
    end
  end

  assert posts(:welcome).reload.people.empty?
  assert posts(:welcome).people.reload.empty?
end
test_dynamic_find_should_respect_association_include() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 727
def test_dynamic_find_should_respect_association_include
  # SQL error in sort clause if :include is not included
  # due to Unknown column 'comments.id'
  assert Person.find(1).posts_with_comments_sorted_by_comment_id.find_by_title("Welcome to the weblog")
end
test_explicitly_joining_join_table() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1113
def test_explicitly_joining_join_table
  assert_equal owners(:blackbeard).toys, owners(:blackbeard).toys.with_pet
end
test_find_on_has_many_association_collection_with_include_and_conditions() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 799
def test_find_on_has_many_association_collection_with_include_and_conditions
  post_with_no_comments = people(:michael).posts_with_no_comments.first
  assert_equal post_with_no_comments, posts(:authorless)
end
test_get_collection_singular_ids_on_has_many_through_with_conditions_and_include() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1003
def test_get_collection_singular_ids_on_has_many_through_with_conditions_and_include
  person = Person.first
  assert_equal person.posts_with_no_comment_ids, person.posts_with_no_comments.map(&:id)
end
test_get_has_many_through_belongs_to_ids_with_conditions() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 999
def test_get_has_many_through_belongs_to_ids_with_conditions
  assert_equal [categories(:general).id], authors(:mary).categories_like_general_ids
end
test_get_ids() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 741
def test_get_ids
  assert_equal [posts(:welcome).id, posts(:authorless).id].sort, people(:michael).post_ids.sort
end
test_get_ids_for_has_many_through_with_conditions_should_not_preload() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 745
def test_get_ids_for_has_many_through_with_conditions_should_not_preload
  Tagging.create!(taggable_type: "Post", taggable_id: posts(:welcome).id, tag: tags(:misc))
  assert_not_called(ActiveRecord::Associations::Preloader, :new) do
    posts(:welcome).misc_tag_ids
  end
end
test_get_ids_for_loaded_associations() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 752
def test_get_ids_for_loaded_associations
  person = people(:michael)
  person.posts.reload
  assert_queries(0) do
    person.post_ids
    person.post_ids
  end
end
test_get_ids_for_unloaded_associations_does_not_load_them() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 761
def test_get_ids_for_unloaded_associations_does_not_load_them
  person = people(:michael)
  assert !person.posts.loaded?
  assert_equal [posts(:welcome).id, posts(:authorless).id].sort, person.post_ids.sort
  assert !person.posts.loaded?
end
test_has_many_association_through_a_belongs_to_association() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 781
def test_has_many_association_through_a_belongs_to_association
  author = authors(:mary)
  post = Post.create!(author: author, title: "TITLE", body: "BODY")
  author.author_favorites.create(favorite_author_id: 1)
  author.author_favorites.create(favorite_author_id: 2)
  author.author_favorites.create(favorite_author_id: 3)
  assert_equal post.author.author_favorites, post.author_favorites
end
test_has_many_association_through_a_belongs_to_association_where_the_association_doesnt_exist() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 776
def test_has_many_association_through_a_belongs_to_association_where_the_association_doesnt_exist
  post = Post.create!(title: "TITLE", body: "BODY")
  assert_equal [], post.author_favorites
end
test_has_many_association_through_a_has_many_association_to_self() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 816
def test_has_many_association_through_a_has_many_association_to_self
  sarah = Person.create!(first_name: "Sarah", primary_contact_id: people(:susan).id, gender: "F", number1_fan_id: 1)
  john = Person.create!(first_name: "John", primary_contact_id: sarah.id, gender: "M", number1_fan_id: 1)
  assert_equal sarah.agents, [john]
  assert_equal people(:susan).agents.flat_map(&:agents).sort, people(:susan).agents_of_agents.sort
end
test_has_many_association_through_a_has_many_association_with_nonstandard_primary_keys() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 795
def test_has_many_association_through_a_has_many_association_with_nonstandard_primary_keys
  assert_equal 2, owners(:blackbeard).toys.count
end
test_has_many_through_add_with_sti_middle_relation() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1202
def test_has_many_through_add_with_sti_middle_relation
  club = SuperClub.create!(name: "Fight Club")
  member = Member.create!(name: "Tyler Durden")

  club.members << member
  assert_equal 1, SuperMembership.where(member_id: member.id, club_id: club.id).count
end
test_has_many_through_associations_on_new_records_use_null_relations() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1154
def test_has_many_through_associations_on_new_records_use_null_relations
  person = Person.new

  assert_no_queries(ignore_none: false) do
    assert_equal [], person.posts
    assert_equal [], person.posts.where(body: "omg")
    assert_equal [], person.posts.pluck(:body)
    assert_equal 0,  person.posts.sum(:tags_count)
    assert_equal 0,  person.posts.count
  end
end
test_has_many_through_associations_sum_on_columns() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1128
def test_has_many_through_associations_sum_on_columns
  post1 = Post.create(title: "active", body: "sample")
  post2 = Post.create(title: "inactive", body: "sample")

  person1 = Person.create(first_name: "aaron", followers_count: 1)
  person2 = Person.create(first_name: "schmit", followers_count: 2)
  person3 = Person.create(first_name: "bill", followers_count: 3)
  person4 = Person.create(first_name: "cal", followers_count: 4)

  Reader.create(post_id: post1.id, person_id: person1.id)
  Reader.create(post_id: post1.id, person_id: person2.id)
  Reader.create(post_id: post1.id, person_id: person3.id)
  Reader.create(post_id: post1.id, person_id: person4.id)

  Reader.create(post_id: post2.id, person_id: person1.id)
  Reader.create(post_id: post2.id, person_id: person2.id)
  Reader.create(post_id: post2.id, person_id: person3.id)
  Reader.create(post_id: post2.id, person_id: person4.id)

  active_persons = Person.joins(:readers).joins(:posts).distinct(true).where("posts.title" => "active")

  assert_equal active_persons.map(&:followers_count).reduce(:+), 10
  assert_equal active_persons.sum(:followers_count), 10
  assert_equal active_persons.sum(:followers_count), active_persons.map(&:followers_count).reduce(:+)
end
test_has_many_through_belongs_to_should_update_when_the_through_foreign_key_changes() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1013
def test_has_many_through_belongs_to_should_update_when_the_through_foreign_key_changes
  post = posts(:eager_other)

  post.author_categorizations
  proxy = post.send(:association_instance_get, :author_categorizations)

  assert !proxy.stale_target?
  assert_equal authors(:mary).categorizations.sort_by(&:id), post.author_categorizations.sort_by(&:id)

  post.author_id = authors(:david).id

  assert proxy.stale_target?
  assert_equal authors(:david).categorizations.sort_by(&:id), post.author_categorizations.sort_by(&:id)
end
test_has_many_through_do_not_cache_association_reader_if_the_though_method_has_default_scopes() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1225
def test_has_many_through_do_not_cache_association_reader_if_the_though_method_has_default_scopes
  member = Member.create!
  club = Club.create!
  TenantMembership.create!(
    member: member,
    club: club
  )

  TenantMembership.current_member = member

  tenant_clubs = member.tenant_clubs
  assert_equal [club], tenant_clubs

  TenantMembership.current_member = nil

  other_member = Member.create!
  other_club = Club.create!
  TenantMembership.create!(
    member: other_member,
    club: other_club
  )

  tenant_clubs = other_member.tenant_clubs
  assert_equal [other_club], tenant_clubs
ensure
  TenantMembership.current_member = nil
end
test_has_many_through_has_one_reflection() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 804
def test_has_many_through_has_one_reflection
  assert_equal [comments(:eager_sti_on_associations_vs_comment)], authors(:david).very_special_comments
end
test_has_many_through_obeys_order_on_through_association() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1122
def test_has_many_through_obeys_order_on_through_association
  owner = owners(:blackbeard)
  assert_includes owner.toys.to_sql, "pets.name desc"
  assert_equal ["parrot", "bulbul"], owner.toys.map { |r| r.pet.name }
end
test_has_many_through_polymorphic_with_primary_key_option() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 946
def test_has_many_through_polymorphic_with_primary_key_option
  assert_equal [categories(:general)], authors(:david).essay_categories

  authors = Author.joins(:essay_categories).where("categories.id" => categories(:general).id)
  assert_equal authors(:david), authors.first

  assert_equal [owners(:blackbeard)], authors(:david).essay_owners

  authors = Author.joins(:essay_owners).where("owners.name = 'blackbeard'")
  assert_equal authors(:david), authors.first
end
test_has_many_through_polymorphic_with_rewhere() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 939
def test_has_many_through_polymorphic_with_rewhere
  post = TaggedPost.create!(title: "Tagged", body: "Post")
  tag = post.tags.create!(name: "Tag")
  assert_equal [tag], TaggedPost.preload(:tags).last.tags
  assert_equal [tag], TaggedPost.eager_load(:tags).last.tags
end
test_has_many_through_unscope_default_scope() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1190
def test_has_many_through_unscope_default_scope
  post = Post.create!(title: "Beaches", body: "I like beaches!")
  Reader.create! person: people(:david), post: post
  LazyReader.create! person: people(:susan), post: post

  assert_equal 2, post.people.to_a.size
  assert_equal 1, post.lazy_people.to_a.size

  assert_equal 2, post.lazy_readers_unscope_skimmers.to_a.size
  assert_equal 2, post.lazy_people_unscope_skimmers.to_a.size
end
test_has_many_through_with_default_scope_on_join_model() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 972
def test_has_many_through_with_default_scope_on_join_model
  assert_equal posts(:welcome).comments.order("id").to_a, authors(:david).comments_on_first_posts
end
test_has_many_through_with_default_scope_on_the_target() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1166
def test_has_many_through_with_default_scope_on_the_target
  person = people(:michael)
  assert_equal [posts(:thinking).id], person.first_posts.map(&:id)

  readers(:michael_authorless).update(first_post_id: 1)
  assert_equal [posts(:thinking).id], person.reload.first_posts.map(&:id)
end
test_has_many_through_with_includes_in_through_association_scope() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1174
def test_has_many_through_with_includes_in_through_association_scope
  assert_not_empty posts(:welcome).author_address_extra_with_address
end
test_has_many_through_with_polymorphic_source() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1117
def test_has_many_through_with_polymorphic_source
  post = tags(:general).tagged_posts.create! title: "foo", body: "bar"
  assert_equal [tags(:general)], post.reload.tags
end
test_has_many_through_with_primary_key_option() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 958
def test_has_many_through_with_primary_key_option
  assert_equal [categories(:general)], authors(:david).essay_categories_2

  authors = Author.joins(:essay_categories_2).where("categories.id" => categories(:general).id)
  assert_equal authors(:david), authors.first
end
test_has_many_through_with_scope_should_respect_table_alias() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1253
def test_has_many_through_with_scope_should_respect_table_alias
  family = Family.create!
  users = 3.times.map { User.create! }
  FamilyTree.create!(member: users[0], family: family)
  FamilyTree.create!(member: users[1], family: family)
  FamilyTree.create!(member: users[2], family: family, token: "wat")

  assert_equal 2, users[0].family_members.to_a.size
  assert_equal 0, users[2].family_members.to_a.size
end
test_has_many_through_with_scope_that_should_not_be_fully_merged() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1218
def test_has_many_through_with_scope_that_should_not_be_fully_merged
  Club.has_many :distinct_memberships, -> { distinct }, class_name: "Membership"
  Club.has_many :special_favourites, through: :distinct_memberships, source: :member

  assert_nil Club.new.special_favourites.distinct_value
end
test_include?() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 161
def test_include?
  person = Person.new
  post = Post.new
  person.posts << post
  assert_includes person.posts, post
end
test_include_method_in_association_through_should_return_true_for_instance_added_with_build() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 914
def test_include_method_in_association_through_should_return_true_for_instance_added_with_build
  person = Person.new
  reference = person.references.build
  job = reference.build_job
  assert_includes person.jobs, job
end
test_include_method_in_association_through_should_return_true_for_instance_added_with_nested_builds() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 921
def test_include_method_in_association_through_should_return_true_for_instance_added_with_nested_builds
  author = Author.new
  post = author.posts.build
  comment = post.comments.build
  assert_includes author.comments, comment
end
test_incorrectly_ordered_through_associations() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1283
def test_incorrectly_ordered_through_associations
  assert_raises(ActiveRecord::HasManyThroughOrderError) do
    DeveloperWithIncorrectlyOrderedHasManyThrough.create(
      companies: [Company.create]
    )
  end
end
test_inner_join_with_quoted_table_name() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 737
def test_inner_join_with_quoted_table_name
  assert_equal 2, people(:michael).jobs.size
end
test_insert_records_via_has_many_through_association_with_scope() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1178
def test_insert_records_via_has_many_through_association_with_scope
  club = Club.create!
  member = Member.create!
  Membership.create!(club: club, member: member)

  club.favourites << member
  assert_equal [member], club.favourites

  club.reload
  assert_equal [member], club.favourites
end
test_joining_has_many_through_belongs_to() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 987
def test_joining_has_many_through_belongs_to
  posts = Post.joins(:author_categorizations).order("posts.id").
               where("categorizations.id" => categorizations(:mary_thinking_sti).id)

  assert_equal [posts(:eager_other), posts(:misc_by_mary), posts(:other_by_mary)], posts
end
test_joining_has_many_through_with_distinct() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 981
def test_joining_has_many_through_with_distinct
  mary = Author.joins(:unique_categorized_posts).where(id: authors(:mary).id).first
  assert_equal 1, mary.unique_categorized_posts.length
  assert_equal 1, mary.unique_categorized_post_ids.length
end
test_merge_join_association_with_has_many_through_association_proxy() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 790
def test_merge_join_association_with_has_many_through_association_proxy
  author = authors(:mary)
  assert_nothing_raised { author.comments.ratings.to_sql }
end
test_modifying_has_many_through_has_one_reflection_should_raise() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 808
def test_modifying_has_many_through_has_one_reflection_should_raise
  [
    lambda { authors(:david).very_special_comments = [VerySpecialComment.create!(body: "Gorp!", post_id: 1011), VerySpecialComment.create!(body: "Eep!", post_id: 1012)] },
    lambda { authors(:david).very_special_comments << VerySpecialComment.create!(body: "Hoohah!", post_id: 1013) },
    lambda { authors(:david).very_special_comments.delete(authors(:david).very_special_comments.first) },
  ].each { |block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) }
end
test_no_pk_join_model_callbacks() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 135
def test_no_pk_join_model_callbacks
  lesson, lesson_student, student = make_no_pk_hm_t

  after_destroy_called = false
  lesson_student.after_destroy do
    after_destroy_called = true
  end

  sicp = lesson.new(name: "SICP")
  ben = student.new(name: "Ben Bitdiddle")
  sicp.students << ben
  assert sicp.save!

  sicp.students.reload
  sicp.students.destroy(*student.all.to_a)
  assert after_destroy_called, "after destroy should be called"
end
test_no_pk_join_table_append() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 107
def test_no_pk_join_table_append
  lesson, _, student = make_no_pk_hm_t

  sicp = lesson.new(name: "SICP")
  ben = student.new(name: "Ben Bitdiddle")
  sicp.students << ben
  assert sicp.save!
end
test_no_pk_join_table_delete() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 116
def test_no_pk_join_table_delete
  lesson, lesson_student, student = make_no_pk_hm_t

  sicp = lesson.new(name: "SICP")
  ben = student.new(name: "Ben Bitdiddle")
  louis = student.new(name: "Louis Reasoner")
  sicp.students << ben
  sicp.students << louis
  assert sicp.save!

  sicp.students.reload
  assert_operator lesson_student.count, :>=, 2
  assert_no_difference("student.count") do
    assert_difference("lesson_student.count", -2) do
      sicp.students.destroy(*student.all.to_a)
    end
  end
end
test_ordered_has_many_through() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 69
def test_ordered_has_many_through
  person_prime = Class.new(ActiveRecord::Base) do
    def self.name; "Person"; end

    has_many :readers
    has_many :posts, -> { order("posts.id DESC") }, through: :readers
  end
  posts = person_prime.includes(:posts).first.posts

  assert_operator posts.length, :>, 1
  posts.each_cons(2) do |left, right|
    assert_operator left.id, :>, right.id
  end
end
test_pk_is_not_required_for_join() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 153
def test_pk_is_not_required_for_join
  post  = Post.includes(:scategories).first
  post2 = Post.includes(:categories).first

  assert_operator post.categories.length, :>, 0
  assert_equal post2.categories, post.categories
end
test_preload_sti_middle_relation() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 56
def test_preload_sti_middle_relation
  club = Club.create!(name: "Aaron cool banana club")
  member1 = Member.create!(name: "Aaron")
  member2 = Member.create!(name: "Cat")

  SuperMembership.create! club: club, member: member1
  CurrentMembership.create! club: club, member: member2

  club1 = Club.includes(:members).find_by_id club.id
  assert_equal [member1, member2].sort_by(&:id),
               club1.members.sort_by(&:id)
end
test_preload_sti_rhs_class() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 49
def test_preload_sti_rhs_class
  developers = Developer.includes(:firms).all.to_a
  assert_no_queries do
    developers.each(&:firms)
  end
end
test_preloading_empty_through_association_via_joins() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1093
def test_preloading_empty_through_association_via_joins
  person = Person.create!(first_name: "Gaga")
  person = Person.where(id: person.id).where("readers.id = 1 or 1=1").references(:readers).includes(:posts).to_a.first

  assert person.posts.loaded?, "person.posts should be loaded"
  assert_equal [], person.posts
end
test_preloading_empty_through_with_polymorphic_source_association() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1101
def test_preloading_empty_through_with_polymorphic_source_association
  owner = Owner.create!(name: "Rainbow Unicat")
  pet = Pet.create!(owner: owner)
  person = Person.create!(first_name: "Gaga")
  treasure = Treasure.create!(looter: person)
  non_looted_treasure = Treasure.create!()
  PetTreasure.create!(pet: pet, treasure: treasure, rainbow_color: "Ultra violet indigo")
  PetTreasure.create!(pet: pet, treasure: non_looted_treasure, rainbow_color: "Ultra violet indigo")

  assert_equal [person], Owner.where(name: "Rainbow Unicat").includes(pets: :persons).first.persons.to_a
end
test_primary_key_option_on_source() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1044
def test_primary_key_option_on_source
  post     = posts(:welcome)
  category = categories(:general)
  Categorization.create!(post_id: post.id, named_category_name: category.name)

  assert_equal [category], post.named_categories
  assert_equal [category.name], post.named_category_ids # checks when target loaded
  assert_equal [category.name], post.reload.named_category_ids # checks when target no loaded
end
test_push_with_invalid_join_record() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 657
def test_push_with_invalid_join_record
  repair_validations(Contract) do
    Contract.validate { |r| r.errors[:base] << "Invalid Contract" }

    firm = companies(:first_firm)
    lifo = Developer.new(name: "lifo")
    assert_raises(ActiveRecord::RecordInvalid) { firm.developers << lifo }

    lifo = Developer.create!(name: "lifo")
    assert_raises(ActiveRecord::RecordInvalid) { firm.developers << lifo }
  end
end
test_push_with_invalid_record() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 652
def test_push_with_invalid_record
  firm = companies(:first_firm)
  assert_raises(ActiveRecord::RecordInvalid) { firm.developers << Developer.new(name: "0") }
end
test_replace_association() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 541
def test_replace_association
  assert_queries(4) { posts(:welcome);people(:david);people(:michael); posts(:welcome).people.reload }

  # 1 query to delete the existing reader (michael)
  # 1 query to associate the new reader (david)
  assert_queries(2) do
    posts(:welcome).people = [people(:david)]
  end

  assert_queries(0) {
    assert_includes posts(:welcome).people, people(:david)
    assert_not_includes posts(:welcome).people, people(:michael)
  }

  assert_includes posts(:welcome).reload.people.reload, people(:david)
  assert_not_includes posts(:welcome).reload.people.reload, people(:michael)
end
test_replace_by_id_order_is_preserved() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 570
def test_replace_by_id_order_is_preserved
  posts(:welcome).people.clear
  posts(:welcome).person_ids = [people(:david).id, people(:michael).id]
  assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order("id").map(&:person_id)

  # Test the inverse order in case the first success was a coincidence
  posts(:welcome).people.clear
  posts(:welcome).person_ids = [people(:michael).id, people(:david).id]
  assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order("id").map(&:person_id)
end
test_replace_order_is_preserved() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 559
def test_replace_order_is_preserved
  posts(:welcome).people.clear
  posts(:welcome).people = [people(:david), people(:michael)]
  assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order("id").map(&:person_id)

  # Test the inverse order in case the first success was a coincidence
  posts(:welcome).people.clear
  posts(:welcome).people = [people(:michael), people(:david)]
  assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order("id").map(&:person_id)
end
test_save_bang_should_raise_exception_when_join_record_has_errors() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1075
def test_save_bang_should_raise_exception_when_join_record_has_errors
  repair_validations(Categorization) do
    Categorization.validate { |r| r.errors[:base] << "Invalid Categorization" }
    c = Category.new(name: "Fishing", authors: [Author.first])
    assert_raises(ActiveRecord::RecordInvalid) do
      c.save!
    end
  end
end
test_save_returns_falsy_when_join_record_has_errors() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1085
def test_save_returns_falsy_when_join_record_has_errors
  repair_validations(Categorization) do
    Categorization.validate { |r| r.errors[:base] << "Invalid Categorization" }
    c = Category.new(name: "Fishing", authors: [Author.first])
    assert_not c.save
  end
end
test_select_chosen_fields_only() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 994
def test_select_chosen_fields_only
  author = authors(:david)
  assert_equal ["body", "id"].sort, author.comments.select("comments.body").first.attributes.keys.sort
end
test_should_raise_exception_for_destroying_mismatching_records() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 384
def test_should_raise_exception_for_destroying_mismatching_records
  assert_no_difference ["Person.count", "Reader.count"] do
    assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:welcome).people.destroy(posts(:thinking)) }
  end
end
test_singleton_has_many_through() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 84
def test_singleton_has_many_through
  book         = make_model "Book"
  subscription = make_model "Subscription"
  subscriber   = make_model "Subscriber"

  subscriber.primary_key = "nick"
  subscription.belongs_to :book,       anonymous_class: book
  subscription.belongs_to :subscriber, anonymous_class: subscriber

  book.has_many :subscriptions, anonymous_class: subscription
  book.has_many :subscribers, through: :subscriptions, anonymous_class: subscriber

  anonbook = book.first
  namebook = Book.find anonbook.id

  assert_operator anonbook.subscribers.count, :>, 0
  anonbook.subscribers.each do |s|
    assert_instance_of subscriber, s
  end
  assert_equal namebook.subscribers.map(&:id).sort,
               anonbook.subscribers.map(&:id).sort
end
test_size_of_through_association_should_increase_correctly_when_has_many_association_is_added() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 965
def test_size_of_through_association_should_increase_correctly_when_has_many_association_is_added
  post = posts(:thinking)
  readers = post.readers.size
  post.people << people(:michael)
  assert_equal readers + 1, post.readers.size
end
test_through_association_readonly_should_be_false() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 928
def test_through_association_readonly_should_be_false
  assert !people(:michael).posts.first.readonly?
  assert !people(:michael).posts.to_a.first.readonly?
end
test_through_record_is_built_when_created_with_where() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 598
def test_through_record_is_built_when_created_with_where
  assert_difference("posts(:thinking).readers.count", 1) do
    posts(:thinking).people.where(first_name: "Jeb").create
  end
end
test_through_scope_is_affected_by_unscoping() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1264
def test_through_scope_is_affected_by_unscoping
  author = authors(:david)

  expected = author.comments.to_a
  FirstPost.unscoped do
    assert_equal expected.sort_by(&:id), author.comments_on_first_posts.sort_by(&:id)
  end
end
test_through_scope_isnt_affected_by_scoping() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1273
def test_through_scope_isnt_affected_by_scoping
  author = authors(:david)

  expected = author.comments_on_first_posts.to_a
  FirstPost.where(id: 2).scoping do
    author.comments_on_first_posts.reset
    assert_equal expected.sort_by(&:id), author.comments_on_first_posts.sort_by(&:id)
  end
end
test_update_counter_caches_on_delete() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 490
def test_update_counter_caches_on_delete
  post = posts(:welcome)
  tag  = post.tags.create!(name: "doomed")

  assert_difference ["post.reload.tags_count"], -1 do
    posts(:welcome).tags.delete(tag)
  end
end
test_update_counter_caches_on_delete_with_dependent_destroy() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 499
def test_update_counter_caches_on_delete_with_dependent_destroy
  post = posts(:welcome)
  tag  = post.tags.create!(name: "doomed")
  post.update_columns(tags_with_destroy_count: post.tags.count)

  assert_difference ["post.reload.tags_with_destroy_count"], -1 do
    posts(:welcome).tags_with_destroy.delete(tag)
  end
end
test_update_counter_caches_on_delete_with_dependent_nullify() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 509
def test_update_counter_caches_on_delete_with_dependent_nullify
  post = posts(:welcome)
  tag  = post.tags.create!(name: "doomed")
  post.update_columns(tags_with_nullify_count: post.tags.count)

  assert_no_difference "post.reload.tags_count" do
    assert_difference "post.reload.tags_with_nullify_count", -1 do
      posts(:welcome).tags_with_nullify.delete(tag)
    end
  end
end
test_update_counter_caches_on_destroy() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 532
def test_update_counter_caches_on_destroy
  post = posts(:welcome)
  tag  = post.tags.create!(name: "doomed")

  assert_difference "post.reload.tags_count", -1 do
    tag.tagged_posts.destroy(post)
  end
end
test_update_counter_caches_on_replace_association() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 521
def test_update_counter_caches_on_replace_association
  post = posts(:welcome)
  tag  = post.tags.create!(name: "doomed")
  tag.tagged_posts << posts(:thinking)

  tag.tagged_posts = []
  post.reload

  assert_equal(post.taggings.count, post.tags_count)
end

Private Instance Methods

make_model(name) click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1292
def make_model(name)
  Class.new(ActiveRecord::Base) { define_singleton_method(:name) { name } }
end
make_no_pk_hm_t() click to toggle source
# File activerecord/test/cases/associations/has_many_through_associations_test.rb, line 1296
def make_no_pk_hm_t
  lesson = make_model "Lesson"
  student = make_model "Student"

  lesson_student = make_model "LessonStudent"
  lesson_student.table_name = "lessons_students"

  lesson_student.belongs_to :lesson, anonymous_class: lesson
  lesson_student.belongs_to :student, anonymous_class: student
  lesson.has_many :lesson_students, anonymous_class: lesson_student
  lesson.has_many :students, through: :lesson_students, anonymous_class: student
  [lesson, lesson_student, student]
end