aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test/cases/associations
diff options
context:
space:
mode:
authorJon Leighton <j@jonathanleighton.com>2011-03-02 21:24:56 +0000
committerJon Leighton <j@jonathanleighton.com>2011-03-04 09:30:27 +0000
commit735844db712c511dd8abf36a5279318fbc0ff9d0 (patch)
tree5fbd5d224ef85d8c878bf221db98b422c9345466 /activerecord/test/cases/associations
parent9a98c766e045aebc2ef6d5b716936b73407f095d (diff)
parentb171b9e73dcc6a89b1da652da61c5127fe605b51 (diff)
downloadrails-735844db712c511dd8abf36a5279318fbc0ff9d0.tar.gz
rails-735844db712c511dd8abf36a5279318fbc0ff9d0.tar.bz2
rails-735844db712c511dd8abf36a5279318fbc0ff9d0.zip
Merge branch 'master' into nested_has_many_through
Conflicts: activerecord/CHANGELOG activerecord/lib/active_record/association_preload.rb activerecord/lib/active_record/associations.rb activerecord/lib/active_record/associations/class_methods/join_dependency.rb activerecord/lib/active_record/associations/class_methods/join_dependency/join_association.rb activerecord/lib/active_record/associations/has_many_association.rb activerecord/lib/active_record/associations/has_many_through_association.rb activerecord/lib/active_record/associations/has_one_association.rb activerecord/lib/active_record/associations/has_one_through_association.rb activerecord/lib/active_record/associations/through_association_scope.rb activerecord/lib/active_record/reflection.rb activerecord/test/cases/associations/has_many_through_associations_test.rb activerecord/test/cases/associations/has_one_through_associations_test.rb activerecord/test/cases/reflection_test.rb activerecord/test/cases/relations_test.rb activerecord/test/fixtures/memberships.yml activerecord/test/models/categorization.rb activerecord/test/models/category.rb activerecord/test/models/member.rb activerecord/test/models/reference.rb activerecord/test/models/tagging.rb
Diffstat (limited to 'activerecord/test/cases/associations')
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb233
-rw-r--r--activerecord/test/cases/associations/callbacks_test.rb9
-rw-r--r--activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb1
-rw-r--r--activerecord/test/cases/associations/eager_load_nested_include_test.rb2
-rw-r--r--activerecord/test/cases/associations/eager_test.rb114
-rw-r--r--activerecord/test/cases/associations/extension_test.rb23
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb126
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb80
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb316
-rw-r--r--activerecord/test/cases/associations/has_one_associations_test.rb139
-rw-r--r--activerecord/test/cases/associations/has_one_through_associations_test.rb71
-rw-r--r--activerecord/test/cases/associations/identity_map_test.rb137
-rw-r--r--activerecord/test/cases/associations/inner_join_association_test.rb16
-rw-r--r--activerecord/test/cases/associations/inverse_associations_test.rb112
-rw-r--r--activerecord/test/cases/associations/join_model_test.rb49
-rw-r--r--activerecord/test/cases/associations/nested_through_associations_test.rb258
16 files changed, 1182 insertions, 504 deletions
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index 1820f95261..9006914508 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -17,7 +17,7 @@ require 'models/essay'
class BelongsToAssociationsTest < ActiveRecord::TestCase
fixtures :accounts, :companies, :developers, :projects, :topics,
:developers_projects, :computers, :authors, :author_addresses,
- :posts, :tags, :taggings, :comments
+ :posts, :tags, :taggings, :comments, :sponsors, :members
def test_belongs_to
Client.find(3).firm.name
@@ -50,11 +50,6 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_nothing_raised { account.firm = account.firm }
end
- def test_triple_equality
- assert Client.find(3).firm === Firm
- assert Firm === Client.find(3).firm
- end
-
def test_type_mismatch
assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = 1 }
assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = Project.find(1) }
@@ -78,27 +73,14 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
Firm.create("name" => "Apple")
Client.create("name" => "Citibank", :firm_name => "Apple")
citibank_result = Client.find(:first, :conditions => {:name => "Citibank"}, :include => :firm_with_primary_key)
- assert_not_nil citibank_result.instance_variable_get("@firm_with_primary_key")
+ assert citibank_result.association_cache.key?(:firm_with_primary_key)
end
def test_eager_loading_with_primary_key_as_symbol
Firm.create("name" => "Apple")
Client.create("name" => "Citibank", :firm_name => "Apple")
citibank_result = Client.find(:first, :conditions => {:name => "Citibank"}, :include => :firm_with_primary_key_symbols)
- assert_not_nil citibank_result.instance_variable_get("@firm_with_primary_key_symbols")
- end
-
- def test_no_unexpected_aliasing
- first_firm = companies(:first_firm)
- another_firm = companies(:another_firm)
-
- citibank = Account.create("credit_limit" => 10)
- citibank.firm = first_firm
- original_proxy = citibank.firm
- citibank.firm = another_firm
-
- assert_equal first_firm.object_id, original_proxy.target.object_id
- assert_equal another_firm.object_id, citibank.firm.target.object_id
+ assert citibank_result.association_cache.key?(:firm_with_primary_key_symbols)
end
def test_creating_the_belonging_object
@@ -133,6 +115,23 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_equal apple.name, client.firm_name
end
+ def test_create!
+ client = Client.create!(:name => "Jimmy")
+ account = client.create_account!(:credit_limit => 10)
+ assert_equal account, client.account
+ assert account.persisted?
+ client.save
+ client.reload
+ assert_equal account, client.account
+ end
+
+ def test_failing_create!
+ client = Client.create!(:name => "Jimmy")
+ assert_raise(ActiveRecord::RecordInvalid) { client.create_account! }
+ assert_not_nil client.account
+ assert client.account.new_record?
+ end
+
def test_natural_assignment_to_nil
client = Client.find(3)
client.firm = nil
@@ -159,6 +158,15 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_not_nil Company.find(3).firm_with_condition, "Microsoft should have a firm"
end
+ def test_with_polymorphic_and_condition
+ sponsor = Sponsor.create
+ member = Member.create :name => "Bert"
+ sponsor.sponsorable = member
+
+ assert_equal member, sponsor.sponsorable
+ assert_nil sponsor.sponsorable_with_conditions
+ end
+
def test_with_select
assert_equal Company.find(2).firm_with_select.attributes.size, 1
assert_equal Company.find(2, :include => :firm_with_select ).firm_with_select.attributes.size, 1
@@ -175,17 +183,6 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_equal 0, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply deleted"
end
- def test_belongs_to_with_primary_key_counter
- debate = Topic.create("title" => "debate")
- assert_equal 0, debate.send(:read_attribute, "replies_count"), "No replies yet"
-
- trash = debate.replies_with_primary_key.create("title" => "blah!", "content" => "world around!")
- assert_equal 1, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply created"
-
- trash.destroy
- assert_equal 0, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply deleted"
- end
-
def test_belongs_to_counter_with_assigning_nil
p = Post.find(1)
c = Comment.find(1)
@@ -198,16 +195,23 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_equal 1, Post.find(p.id).comments.size
end
- def test_belongs_to_with_primary_key_counter_with_assigning_nil
- debate = Topic.create("title" => "debate")
- reply = Reply.create("title" => "blah!", "content" => "world around!", "parent_title" => "debate")
+ def test_belongs_to_with_primary_key_counter
+ debate = Topic.create("title" => "debate")
+ debate2 = Topic.create("title" => "debate2")
+ reply = Reply.create("title" => "blah!", "content" => "world around!", "parent_title" => "debate")
+
+ assert_equal 1, debate.reload.replies_count
+ assert_equal 0, debate2.reload.replies_count
- assert_equal debate.title, reply.parent_title
- assert_equal 1, Topic.find(debate.id).send(:read_attribute, "replies_count")
+ reply.topic_with_primary_key = debate2
+
+ assert_equal 0, debate.reload.replies_count
+ assert_equal 1, debate2.reload.replies_count
reply.topic_with_primary_key = nil
- assert_equal 0, Topic.find(debate.id).send(:read_attribute, "replies_count")
+ assert_equal 0, debate.reload.replies_count
+ assert_equal 0, debate2.reload.replies_count
end
def test_belongs_to_counter_with_reassigning
@@ -311,13 +315,21 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_equal Firm.find(:first, :order => "id"), c.firm_with_basic_id
end
- def test_forgetting_the_load_when_foreign_key_enters_late
- c = Client.new
- assert_nil c.firm_with_basic_id
+ def test_setting_foreign_key_after_nil_target_loaded
+ client = Client.new
+ client.firm_with_basic_id
+ client.firm_id = 1
- c.firm_id = 1
- # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
- assert_equal Firm.find(:first, :order => "id"), c.firm_with_basic_id
+ assert_equal companies(:first_firm), client.firm_with_basic_id
+ end
+
+ def test_polymorphic_setting_foreign_key_after_nil_target_loaded
+ sponsor = Sponsor.new
+ sponsor.sponsorable
+ sponsor.sponsorable_id = 1
+ sponsor.sponsorable_type = "Member"
+
+ assert_equal members(:groucho), sponsor.sponsorable
end
def test_field_name_same_as_foreign_key
@@ -419,6 +431,18 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_nil sponsor.sponsorable_id
end
+ def test_assignment_updates_foreign_id_field_for_new_and_saved_records
+ client = Client.new
+ saved_firm = Firm.create :name => "Saved"
+ new_firm = Firm.new
+
+ client.firm = saved_firm
+ assert_equal saved_firm.id, client.client_of
+
+ client.firm = new_firm
+ assert_nil client.client_of
+ end
+
def test_polymorphic_assignment_with_primary_key_updates_foreign_id_field_for_new_and_saved_records
essay = Essay.new
saved_writer = Author.create(:name => "David")
@@ -488,39 +512,118 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
end
def test_reassigning_the_parent_id_updates_the_object
- original_parent = Firm.create! :name => "original"
- updated_parent = Firm.create! :name => "updated"
+ client = companies(:second_client)
+
+ client.firm
+ client.firm_with_condition
+ firm_proxy = client.send(:association_instance_get, :firm)
+ firm_with_condition_proxy = client.send(:association_instance_get, :firm_with_condition)
- client = Client.new("client_of" => original_parent.id)
- assert_equal original_parent, client.firm
- assert_equal original_parent, client.firm_with_condition
- assert_equal original_parent, client.firm_with_other_name
+ assert !firm_proxy.stale_target?
+ assert !firm_with_condition_proxy.stale_target?
+ assert_equal companies(:first_firm), client.firm
+ assert_equal companies(:first_firm), client.firm_with_condition
- client.client_of = updated_parent.id
- assert_equal updated_parent, client.firm
- assert_equal updated_parent, client.firm_with_condition
- assert_equal updated_parent, client.firm_with_other_name
+ client.client_of = companies(:another_firm).id
+
+ assert firm_proxy.stale_target?
+ assert firm_with_condition_proxy.stale_target?
+ assert_equal companies(:another_firm), client.firm
+ assert_equal companies(:another_firm), client.firm_with_condition
end
def test_polymorphic_reassignment_of_associated_id_updates_the_object
- member1 = Member.create!
- member2 = Member.create!
+ sponsor = sponsors(:moustache_club_sponsor_for_groucho)
+
+ sponsor.sponsorable
+ proxy = sponsor.send(:association_instance_get, :sponsorable)
- sponsor = Sponsor.new("sponsorable_type" => "Member", "sponsorable_id" => member1.id)
- assert_equal member1, sponsor.sponsorable
+ assert !proxy.stale_target?
+ assert_equal members(:groucho), sponsor.sponsorable
- sponsor.sponsorable_id = member2.id
- assert_equal member2, sponsor.sponsorable
+ sponsor.sponsorable_id = members(:some_other_guy).id
+
+ assert proxy.stale_target?
+ assert_equal members(:some_other_guy), sponsor.sponsorable
end
def test_polymorphic_reassignment_of_associated_type_updates_the_object
- member1 = Member.create!
+ sponsor = sponsors(:moustache_club_sponsor_for_groucho)
+
+ sponsor.sponsorable
+ proxy = sponsor.send(:association_instance_get, :sponsorable)
+
+ assert !proxy.stale_target?
+ assert_equal members(:groucho), sponsor.sponsorable
- sponsor = Sponsor.new("sponsorable_type" => "Member", "sponsorable_id" => member1.id)
- assert_equal member1, sponsor.sponsorable
+ sponsor.sponsorable_type = 'Firm'
- sponsor.sponsorable_type = "Firm"
- assert_not_equal member1, sponsor.sponsorable
+ assert proxy.stale_target?
+ assert_equal companies(:first_firm), sponsor.sponsorable
end
+ def test_reloading_association_with_key_change
+ client = companies(:second_client)
+ firm = client.association(:firm)
+
+ client.firm = companies(:another_firm)
+ firm.reload
+ assert_equal companies(:another_firm), firm.target
+
+ client.client_of = companies(:first_firm).id
+ firm.reload
+ assert_equal companies(:first_firm), firm.target
+ end
+
+ def test_polymorphic_counter_cache
+ tagging = taggings(:welcome_general)
+ post = posts(:welcome)
+ comment = comments(:greetings)
+
+ assert_difference 'post.reload.taggings_count', -1 do
+ assert_difference 'comment.reload.taggings_count', +1 do
+ tagging.taggable = comment
+ end
+ end
+ end
+
+ def test_polymorphic_with_custom_foreign_type
+ sponsor = sponsors(:moustache_club_sponsor_for_groucho)
+ groucho = members(:groucho)
+ other = members(:some_other_guy)
+
+ assert_equal groucho, sponsor.sponsorable
+ assert_equal groucho, sponsor.thing
+
+ sponsor.thing = other
+
+ assert_equal other, sponsor.sponsorable
+ assert_equal other, sponsor.thing
+
+ sponsor.sponsorable = groucho
+
+ assert_equal groucho, sponsor.sponsorable
+ assert_equal groucho, sponsor.thing
+ end
+
+ def test_build_with_conditions
+ client = companies(:second_client)
+ firm = client.build_bob_firm
+
+ assert_equal "Bob", firm.name
+ end
+
+ def test_create_with_conditions
+ client = companies(:second_client)
+ firm = client.create_bob_firm
+
+ assert_equal "Bob", firm.name
+ end
+
+ def test_create_bang_with_conditions
+ client = companies(:second_client)
+ firm = client.create_bob_firm!
+
+ assert_equal "Bob", firm.name
+ end
end
diff --git a/activerecord/test/cases/associations/callbacks_test.rb b/activerecord/test/cases/associations/callbacks_test.rb
index 6a30e2905b..2d0d4541b4 100644
--- a/activerecord/test/cases/associations/callbacks_test.rb
+++ b/activerecord/test/cases/associations/callbacks_test.rb
@@ -3,6 +3,7 @@ require 'models/post'
require 'models/author'
require 'models/project'
require 'models/developer'
+require 'models/company'
class AssociationCallbacksTest < ActiveRecord::TestCase
fixtures :posts, :authors, :projects, :developers
@@ -81,6 +82,14 @@ class AssociationCallbacksTest < ActiveRecord::TestCase
assert_equal callback_log, jack.post_log
end
+ def test_has_many_callbacks_for_destroy_on_parent
+ firm = Firm.create! :name => "Firm"
+ client = firm.clients.create! :name => "Client"
+ firm.destroy
+
+ assert_equal ["before_remove#{client.id}", "after_remove#{client.id}"], firm.log
+ end
+
def test_has_and_belongs_to_many_add_callback
david = developers(:david)
ar = projects(:active_record)
diff --git a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb
index fb59f63f91..d75791cab9 100644
--- a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb
+++ b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb
@@ -27,6 +27,7 @@ class EagerLoadIncludeFullStiClassNamesTest < ActiveRecord::TestCase
post = Namespaced::Post.find_by_title( 'Great stuff', :include => :tagging )
assert_nil post.tagging
+ ActiveRecord::IdentityMap.clear
ActiveRecord::Base.store_full_sti_class = true
post = Namespaced::Post.find_by_title( 'Great stuff', :include => :tagging )
assert_instance_of Tagging, post.tagging
diff --git a/activerecord/test/cases/associations/eager_load_nested_include_test.rb b/activerecord/test/cases/associations/eager_load_nested_include_test.rb
index c7671a8c22..2cf9f89c3c 100644
--- a/activerecord/test/cases/associations/eager_load_nested_include_test.rb
+++ b/activerecord/test/cases/associations/eager_load_nested_include_test.rb
@@ -1,9 +1,11 @@
require 'cases/helper'
require 'models/post'
+require 'models/tag'
require 'models/author'
require 'models/comment'
require 'models/category'
require 'models/categorization'
+require 'models/tagging'
require 'active_support/core_ext/array/random_access'
module Remembered
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 949fbb9300..ed6337b596 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -17,18 +17,28 @@ require 'models/subscription'
require 'models/book'
require 'models/developer'
require 'models/project'
+require 'models/member'
+require 'models/membership'
+require 'models/club'
+require 'models/categorization'
+require 'models/sponsor'
class EagerAssociationTest < ActiveRecord::TestCase
fixtures :posts, :comments, :authors, :author_addresses, :categories, :categories_posts,
- :companies, :accounts, :tags, :taggings, :people, :readers,
+ :companies, :accounts, :tags, :taggings, :people, :readers, :categorizations,
:owners, :pets, :author_favorites, :jobs, :references, :subscribers, :subscriptions, :books,
- :developers, :projects, :developers_projects
+ :developers, :projects, :developers_projects, :members, :memberships, :clubs, :sponsors
def setup
# preheat table existence caches
Comment.find_by_id(1)
end
+ def test_eager_with_has_one_through_join_model_with_conditions_on_the_through
+ member = Member.find(members(:some_other_guy).id, :include => :favourite_club)
+ assert_nil member.favourite_club
+ end
+
def test_loading_with_one_association
posts = Post.find(:all, :include => :comments)
post = posts.find { |p| p.id == 1 }
@@ -110,30 +120,29 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_load_associated_records_in_one_query_when_adapter_has_no_limit
Post.connection.expects(:in_clause_length).at_least_once.returns(nil)
- Post.expects(:i_was_called).with([1,2,3,4,5,6,7]).returns([1])
- associated_records = Post.send(:associated_records, [1,2,3,4,5,6,7]) do |some_ids|
- Post.i_was_called(some_ids)
+
+ post = posts(:welcome)
+ assert_queries(2) do
+ Post.includes(:comments).where(:id => post.id).to_a
end
- assert_equal [1], associated_records
end
def test_load_associated_records_in_several_queries_when_many_ids_passed
- Post.connection.expects(:in_clause_length).at_least_once.returns(5)
- Post.expects(:i_was_called).with([1,2,3,4,5]).returns([1])
- Post.expects(:i_was_called).with([6,7]).returns([6])
- associated_records = Post.send(:associated_records, [1,2,3,4,5,6,7]) do |some_ids|
- Post.i_was_called(some_ids)
+ Post.connection.expects(:in_clause_length).at_least_once.returns(1)
+
+ post1, post2 = posts(:welcome), posts(:thinking)
+ assert_queries(3) do
+ Post.includes(:comments).where(:id => [post1.id, post2.id]).to_a
end
- assert_equal [1,6], associated_records
end
def test_load_associated_records_in_one_query_when_a_few_ids_passed
- Post.connection.expects(:in_clause_length).at_least_once.returns(5)
- Post.expects(:i_was_called).with([1,2,3]).returns([1])
- associated_records = Post.send(:associated_records, [1,2,3]) do |some_ids|
- Post.i_was_called(some_ids)
+ Post.connection.expects(:in_clause_length).at_least_once.returns(3)
+
+ post = posts(:welcome)
+ assert_queries(2) do
+ Post.includes(:comments).where(:id => post.id).to_a
end
- assert_equal [1], associated_records
end
def test_including_duplicate_objects_from_belongs_to
@@ -175,7 +184,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
author = authors(:david)
post = author.post_about_thinking_with_last_comment
last_comment = post.last_comment
- author = assert_queries(3) { Author.find(author.id, :include => {:post_about_thinking_with_last_comment => :last_comment})} # find the author, then find the posts, then find the comments
+ author = assert_queries(ActiveRecord::IdentityMap.enabled? ? 2 : 3) { Author.find(author.id, :include => {:post_about_thinking_with_last_comment => :last_comment})} # find the author, then find the posts, then find the comments
assert_no_queries do
assert_equal post, author.post_about_thinking_with_last_comment
assert_equal last_comment, author.post_about_thinking_with_last_comment.last_comment
@@ -186,7 +195,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
post = posts(:welcome)
author = post.author
author_address = author.author_address
- post = assert_queries(3) { Post.find(post.id, :include => {:author_with_address => :author_address}) } # find the post, then find the author, then find the address
+ post = assert_queries(ActiveRecord::IdentityMap.enabled? ? 2 : 3) { Post.find(post.id, :include => {:author_with_address => :author_address}) } # find the post, then find the author, then find the address
assert_no_queries do
assert_equal author, post.author_with_address
assert_equal author_address, post.author_with_address.author_address
@@ -202,6 +211,15 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
end
+ def test_finding_with_includes_on_null_belongs_to_polymorphic_association
+ sponsor = sponsors(:moustache_club_sponsor_for_groucho)
+ sponsor.update_attributes!(:sponsorable => nil)
+ sponsor = assert_queries(1) { Sponsor.find(sponsor.id, :include => :sponsorable) }
+ assert_no_queries do
+ assert_equal nil, sponsor.sponsorable
+ end
+ end
+
def test_loading_from_an_association
posts = authors(:david).posts.find(:all, :include => :comments, :order => "posts.id")
assert_equal 2, posts.first.comments.size
@@ -650,7 +668,11 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_preload_with_interpolation
- assert_equal [comments(:greetings)], Post.find(posts(:welcome).id, :include => :comments_with_interpolated_conditions).comments_with_interpolated_conditions
+ post = Post.includes(:comments_with_interpolated_conditions).find(posts(:welcome).id)
+ assert_equal [comments(:greetings)], post.comments_with_interpolated_conditions
+
+ post = Post.joins(:comments_with_interpolated_conditions).find(posts(:welcome).id)
+ assert_equal [comments(:greetings)], post.comments_with_interpolated_conditions
end
def test_polymorphic_type_condition
@@ -794,18 +816,18 @@ class EagerAssociationTest < ActiveRecord::TestCase
assert_equal [posts(:welcome)], posts
assert_equal authors(:david), assert_no_queries { posts[0].author}
- posts = assert_queries(2) do
+ posts = assert_queries(ActiveRecord::IdentityMap.enabled? ? 1 : 2) do
Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => [:comments], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
end
assert_equal [posts(:welcome)], posts
assert_equal authors(:david), assert_no_queries { posts[0].author}
- posts = assert_queries(2) do
+ posts = assert_queries(ActiveRecord::IdentityMap.enabled? ? 1 : 2) do
Post.find(:all, :include => :author, :joins => {:taggings => :tag}, :conditions => "tags.name = 'General'", :order => 'posts.id')
end
assert_equal posts(:welcome, :thinking), posts
- posts = assert_queries(2) do
+ posts = assert_queries(ActiveRecord::IdentityMap.enabled? ? 1 : 2) do
Post.find(:all, :include => :author, :joins => {:taggings => {:tag => :taggings}}, :conditions => "taggings_tags.super_tag_id=2", :order => 'posts.id')
end
assert_equal posts(:welcome, :thinking), posts
@@ -819,7 +841,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
assert_equal [posts(:welcome)], posts
assert_equal authors(:david), assert_no_queries { posts[0].author}
- posts = assert_queries(2) do
+ posts = assert_queries(ActiveRecord::IdentityMap.enabled? ? 1 : 2) do
Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => ["INNER JOIN comments on comments.post_id = posts.id"], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
end
assert_equal [posts(:welcome)], posts
@@ -836,6 +858,8 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_eager_loading_with_conditions_on_join_model_preloads
+ Author.columns
+
authors = assert_queries(2) do
Author.find(:all, :include => :author_address, :joins => :comments, :conditions => "posts.title like 'Welcome%'")
end
@@ -881,25 +905,55 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_preload_has_one_using_primary_key
- expected = Firm.find(:first).account_using_primary_key
- firm = Firm.find :first, :include => :account_using_primary_key
+ expected = accounts(:signals37)
+ firm = Firm.find :first, :include => :account_using_primary_key, :order => 'companies.id'
assert_no_queries do
assert_equal expected, firm.account_using_primary_key
end
end
def test_include_has_one_using_primary_key
- expected = Firm.find(1).account_using_primary_key
+ expected = accounts(:signals37)
firm = Firm.find(:all, :include => :account_using_primary_key, :order => 'accounts.id').detect {|f| f.id == 1}
assert_no_queries do
assert_equal expected, firm.account_using_primary_key
end
end
- def test_preloading_empty_polymorphic_parent
+ def test_preloading_empty_belongs_to
+ c = Client.create!(:name => 'Foo', :client_of => Company.maximum(:id) + 1)
+
+ client = assert_queries(2) { Client.preload(:firm).find(c.id) }
+ assert_no_queries { assert_nil client.firm }
+ end
+
+ def test_preloading_empty_belongs_to_polymorphic
t = Tagging.create!(:taggable_type => 'Post', :taggable_id => Post.maximum(:id) + 1, :tag => tags(:general))
- assert_queries(2) { @tagging = Tagging.preload(:taggable).find(t.id) }
- assert_no_queries { assert ! @tagging.taggable }
+ tagging = assert_queries(ActiveRecord::IdentityMap.enabled? ? 1 : 2) { Tagging.preload(:taggable).find(t.id) }
+ assert_no_queries { assert_nil tagging.taggable }
+ end
+
+ def test_preloading_through_empty_belongs_to
+ c = Client.create!(:name => 'Foo', :client_of => Company.maximum(:id) + 1)
+
+ client = assert_queries(2) { Client.preload(:accounts).find(c.id) }
+ assert_no_queries { assert client.accounts.empty? }
+ end
+
+ def test_preloading_has_many_through_with_uniq
+ mary = Author.includes(: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
+
+ def test_preloading_polymorphic_with_custom_foreign_type
+ sponsor = sponsors(:moustache_club_sponsor_for_groucho)
+ groucho = members(:groucho)
+
+ sponsor = assert_queries(2) {
+ Sponsor.includes(:thing).where(:id => sponsor.id).first
+ }
+ assert_no_queries { assert_equal groucho, sponsor.thing }
end
end
diff --git a/activerecord/test/cases/associations/extension_test.rb b/activerecord/test/cases/associations/extension_test.rb
index efaab8569e..24830a661a 100644
--- a/activerecord/test/cases/associations/extension_test.rb
+++ b/activerecord/test/cases/associations/extension_test.rb
@@ -30,6 +30,11 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase
assert_equal projects(:active_record), developers(:david).projects_extended_by_name_and_block.find_least_recent
end
+ def test_extension_with_scopes
+ assert_equal comments(:greetings), posts(:welcome).comments.offset(1).find_most_recent
+ assert_equal comments(:greetings), posts(:welcome).comments.not_again.find_most_recent
+ end
+
def test_marshalling_extensions
david = developers(:david)
assert_equal projects(:action_controller), david.projects.find_most_recent
@@ -47,12 +52,16 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase
end
def test_extension_name
- extension = Proc.new {}
- name = :association_name
-
- assert_equal 'DeveloperAssociationNameAssociationExtension', Developer.send(:create_extension_modules, name, extension, []).first.name
- assert_equal 'MyApplication::Business::DeveloperAssociationNameAssociationExtension', MyApplication::Business::Developer.send(:create_extension_modules, name, extension, []).first.name
- assert_equal 'MyApplication::Business::DeveloperAssociationNameAssociationExtension', MyApplication::Business::Developer.send(:create_extension_modules, name, extension, []).first.name
- assert_equal 'MyApplication::Business::DeveloperAssociationNameAssociationExtension', MyApplication::Business::Developer.send(:create_extension_modules, name, extension, []).first.name
+ assert_equal 'DeveloperAssociationNameAssociationExtension', extension_name(Developer)
+ assert_equal 'MyApplication::Business::DeveloperAssociationNameAssociationExtension', extension_name(MyApplication::Business::Developer)
+ assert_equal 'MyApplication::Business::DeveloperAssociationNameAssociationExtension', extension_name(MyApplication::Business::Developer)
end
+
+ private
+
+ def extension_name(model)
+ builder = ActiveRecord::Associations::Builder::HasMany.new(model, :association_name, {}) { }
+ builder.send(:wrap_block_extension)
+ builder.options[:extend].first.name
+ end
end
diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
index 513f76255c..73d02c9676 100644
--- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
@@ -72,7 +72,7 @@ class DeveloperWithCounterSQL < ActiveRecord::Base
:join_table => "developers_projects",
:association_foreign_key => "project_id",
:foreign_key => "developer_id",
- :counter_sql => 'SELECT COUNT(*) AS count_all FROM projects INNER JOIN developers_projects ON projects.id = developers_projects.project_id WHERE developers_projects.developer_id =#{id}'
+ :counter_sql => proc { "SELECT COUNT(*) AS count_all FROM projects INNER JOIN developers_projects ON projects.id = developers_projects.project_id WHERE developers_projects.developer_id =#{id}" }
end
class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
@@ -101,38 +101,6 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_equal 't1', record[1]
end
- def test_should_record_timestamp_for_join_table
- setup_data_for_habtm_case
-
- con = ActiveRecord::Base.connection
- sql = 'select * from countries_treaties'
- record = con.select_rows(sql).last
- assert_not_nil record[2]
- assert_not_nil record[3]
- if current_adapter?(:Mysql2Adapter, :OracleAdapter)
- assert_match %r{\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}}, record[2].to_s(:db)
- assert_match %r{\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}}, record[3].to_s(:db)
- else
- assert_match %r{\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}}, record[2]
- assert_match %r{\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}}, record[3]
- end
- end
-
- def test_should_record_timestamp_for_join_table_only_if_timestamp_should_be_recorded
- begin
- Treaty.record_timestamps = false
- setup_data_for_habtm_case
-
- con = ActiveRecord::Base.connection
- sql = 'select * from countries_treaties'
- record = con.select_rows(sql).last
- assert_nil record[2]
- assert_nil record[3]
- ensure
- Treaty.record_timestamps = true
- end
- end
-
def test_has_and_belongs_to_many
david = Developer.find(1)
@@ -218,34 +186,6 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_equal 2, aredridel.projects(true).size
end
- def test_adding_uses_default_values_on_join_table
- ac = projects(:action_controller)
- assert !developers(:jamis).projects.include?(ac)
- developers(:jamis).projects << ac
-
- assert developers(:jamis, :reload).projects.include?(ac)
- project = developers(:jamis).projects.detect { |p| p == ac }
- assert_equal 1, project.access_level.to_i
- end
-
- def test_habtm_attribute_access_and_respond_to
- project = developers(:jamis).projects[0]
- assert project.has_attribute?("name")
- assert project.has_attribute?("joined_on")
- assert project.has_attribute?("access_level")
- assert project.respond_to?("name")
- assert project.respond_to?("name=")
- assert project.respond_to?("name?")
- assert project.respond_to?("joined_on")
- # given that the 'join attribute' won't be persisted, I don't
- # think we should define the mutators
- #assert project.respond_to?("joined_on=")
- assert project.respond_to?("joined_on?")
- assert project.respond_to?("access_level")
- #assert project.respond_to?("access_level=")
- assert project.respond_to?("access_level?")
- end
-
def test_habtm_adding_before_save
no_of_devels = Developer.count
no_of_projects = Project.count
@@ -425,38 +365,41 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
def test_removing_associations_on_destroy
david = DeveloperWithBeforeDestroyRaise.find(1)
assert !david.projects.empty?
- assert_raise(RuntimeError) { david.destroy }
+ david.destroy
assert david.projects.empty?
assert DeveloperWithBeforeDestroyRaise.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = 1").empty?
end
- def test_additional_columns_from_join_table
- assert_date_from_db Date.new(2004, 10, 10), Developer.find(1).projects.first.joined_on.to_date
- end
-
def test_destroying
david = Developer.find(1)
- active_record = Project.find(1)
+ project = Project.find(1)
david.projects.reload
assert_equal 2, david.projects.size
- assert_equal 3, active_record.developers.size
+ assert_equal 3, project.developers.size
- assert_difference "Project.count", -1 do
- david.projects.destroy(active_record)
+ assert_no_difference "Project.count" do
+ david.projects.destroy(project)
end
+ join_records = Developer.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = #{david.id} AND project_id = #{project.id}")
+ assert join_records.empty?
+
assert_equal 1, david.reload.projects.size
assert_equal 1, david.projects(true).size
end
- def test_destroying_array
+ def test_destroying_many
david = Developer.find(1)
david.projects.reload
+ projects = Project.all
- assert_difference "Project.count", -Project.count do
- david.projects.destroy(Project.find(:all))
+ assert_no_difference "Project.count" do
+ david.projects.destroy(*projects)
end
+ join_records = Developer.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = #{david.id}")
+ assert join_records.empty?
+
assert_equal 0, david.reload.projects.size
assert_equal 0, david.projects(true).size
end
@@ -465,7 +408,14 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
david = Developer.find(1)
david.projects.reload
assert !david.projects.empty?
- david.projects.destroy_all
+
+ assert_no_difference "Project.count" do
+ david.projects.destroy_all
+ end
+
+ join_records = Developer.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = #{david.id}")
+ assert join_records.empty?
+
assert david.projects.empty?
assert david.projects(true).empty?
end
@@ -675,25 +625,6 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_respond_to categories(:technology).select_testing_posts.find(:first), :correctness_marker
end
- def test_updating_attributes_on_rich_associations
- david = projects(:action_controller).developers.first
- david.name = "DHH"
- assert_raise(ActiveRecord::ReadOnlyRecord) { david.save! }
- end
-
- def test_updating_attributes_on_rich_associations_with_limited_find_from_reflection
- david = projects(:action_controller).selected_developers.first
- david.name = "DHH"
- assert_nothing_raised { david.save! }
- end
-
-
- def test_updating_attributes_on_rich_associations_with_limited_find
- david = projects(:action_controller).developers.find(:all, :select => "developers.*").first
- david.name = "DHH"
- assert david.save!
- end
-
def test_join_table_alias
assert_equal 3, Developer.find(:all, :include => {:projects => :developers}, :conditions => 'developers_projects_join.joined_on IS NOT NULL').size
end
@@ -840,10 +771,13 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
david = Developer.find(1)
# clear cache possibly created by other tests
david.projects.reset_column_information
- assert_queries(0) { david.projects.columns; david.projects.columns }
- # and again to verify that reset_column_information clears the cache correctly
+
+ # One query for columns, one for primary key
+ assert_queries(2) { david.projects.columns; david.projects.columns }
+
+ ## and again to verify that reset_column_information clears the cache correctly
david.projects.reset_column_information
- assert_queries(0) { david.projects.columns; david.projects.columns }
+ assert_queries(2) { david.projects.columns; david.projects.columns }
end
def test_attributes_are_being_set_when_initialized_from_habm_association_with_where_clause
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index fb772bb8e6..ad774eb9ce 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -43,7 +43,7 @@ end
class HasManyAssociationsTest < ActiveRecord::TestCase
fixtures :accounts, :categories, :companies, :developers, :projects,
:developers_projects, :topics, :authors, :comments,
- :people, :posts, :readers, :taggings
+ :people, :posts, :readers, :taggings, :cars
def setup
Client.destroyed_client_ids.clear
@@ -66,14 +66,36 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal 'exotic', bulb.name
end
+ # When creating objects on the association, we must not do it within a scope (even though it
+ # would be convenient), because this would cause that scope to be applied to any callbacks etc.
+ def test_build_and_create_should_not_happen_within_scope
+ car = cars(:honda)
+ original_scoped_methods = Bulb.scoped_methods
+
+ bulb = car.bulbs.build
+ assert_equal original_scoped_methods, bulb.scoped_methods_after_initialize
+
+ bulb = car.bulbs.create
+ assert_equal original_scoped_methods, bulb.scoped_methods_after_initialize
+
+ bulb = car.bulbs.create!
+ assert_equal original_scoped_methods, bulb.scoped_methods_after_initialize
+ end
+
def test_no_sql_should_be_fired_if_association_already_loaded
Car.create(:name => 'honda')
bulbs = Car.first.bulbs
bulbs.inspect # to load all instances of bulbs
+
assert_no_queries do
bulbs.first()
bulbs.first({})
end
+
+ assert_no_queries do
+ bulbs.last()
+ bulbs.last({})
+ end
end
def test_create_resets_cached_counters
@@ -257,7 +279,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_counting_using_finder_sql
assert_equal 2, Firm.find(4).clients_using_sql.count
- assert_equal 2, Firm.find(4).clients_using_multiline_sql.count
end
def test_belongs_to_sanity
@@ -608,7 +629,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal topic.replies.to_a.size, topic.replies_count
end
- def test_deleting_updates_counter_cache_without_dependent_destroy
+ def test_deleting_updates_counter_cache_without_dependent_option
post = posts(:welcome)
assert_difference "post.reload.taggings_count", -1 do
@@ -616,6 +637,24 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
end
+ def test_deleting_updates_counter_cache_with_dependent_delete_all
+ post = posts(:welcome)
+ post.update_attribute(:taggings_with_delete_all_count, post.taggings_count)
+
+ assert_difference "post.reload.taggings_with_delete_all_count", -1 do
+ post.taggings_with_delete_all.delete(post.taggings_with_delete_all.first)
+ end
+ end
+
+ def test_deleting_updates_counter_cache_with_dependent_destroy
+ post = posts(:welcome)
+ post.update_attribute(:taggings_with_destroy_count, post.taggings_count)
+
+ assert_difference "post.reload.taggings_with_destroy_count", -1 do
+ post.taggings_with_destroy.delete(post.taggings_with_destroy.first)
+ end
+ end
+
def test_deleting_a_collection
force_signal37_to_load_all_clients_of_firm
companies(:first_firm).clients_of_firm.create("name" => "Another Client")
@@ -628,8 +667,10 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_delete_all
force_signal37_to_load_all_clients_of_firm
companies(:first_firm).clients_of_firm.create("name" => "Another Client")
- assert_equal 2, companies(:first_firm).clients_of_firm.size
- companies(:first_firm).clients_of_firm.delete_all
+ clients = companies(:first_firm).clients_of_firm.to_a
+ assert_equal 2, clients.count
+ deleted = companies(:first_firm).clients_of_firm.delete_all
+ assert_equal clients.sort_by(&:id), deleted.sort_by(&:id)
assert_equal 0, companies(:first_firm).clients_of_firm.size
assert_equal 0, companies(:first_firm).clients_of_firm(true).size
end
@@ -649,11 +690,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
client_id = firm.clients_of_firm.first.id
assert_equal 1, firm.clients_of_firm.size
- firm.clients_of_firm.clear
+ cleared = firm.clients_of_firm.clear
assert_equal 0, firm.clients_of_firm.size
assert_equal 0, firm.clients_of_firm(true).size
assert_equal [], Client.destroyed_client_ids[firm.id]
+ assert_equal firm.clients_of_firm.object_id, cleared.object_id
# Should not be destroyed since the association is not dependent.
assert_nothing_raised do
@@ -664,9 +706,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_clearing_updates_counter_cache
topic = Topic.first
- topic.replies.clear
- topic.reload
- assert_equal 0, topic.replies_count
+ assert_difference 'topic.reload.replies_count', -1 do
+ topic.replies.clear
+ end
end
def test_clearing_a_dependent_association_collection
@@ -963,6 +1005,19 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert !firm.clients.include?(:first_client)
end
+ def test_replace_failure
+ firm = companies(:first_firm)
+ account = Account.new
+ orig_accounts = firm.accounts.to_a
+
+ assert !account.valid?
+ assert !orig_accounts.empty?
+ assert_raise ActiveRecord::RecordNotSaved do
+ firm.accounts = [account]
+ end
+ assert_equal orig_accounts, firm.accounts
+ end
+
def test_get_ids
assert_equal [companies(:first_client).id, companies(:second_client).id], companies(:first_firm).client_ids
end
@@ -1302,4 +1357,11 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal reply.id, first.id
assert_equal true, first.approved?
end
+
+ def test_to_a_should_dup_target
+ ary = topics(:first).replies.to_a
+ target = topics(:first).replies.target
+
+ assert_not_equal target.object_id, ary.object_id
+ end
end
diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index 5fac52257c..9adaebe924 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -20,12 +20,15 @@ require 'models/subscription'
require 'models/essay'
require 'models/category'
require 'models/owner'
+require 'models/categorization'
+require 'models/member'
+require 'models/membership'
+require 'models/club'
class HasManyThroughAssociationsTest < ActiveRecord::TestCase
- fixtures :posts, :readers, :people, :comments, :authors,
- :owners, :pets, :toys, :jobs, :references, :companies,
- :subscribers, :books, :subscriptions, :developers,
- :essays, :categories, :owners
+ fixtures :posts, :readers, :people, :comments, :authors, :categories, :taggings, :tags,
+ :owners, :pets, :toys, :jobs, :references, :companies, :members, :author_addresses,
+ :subscribers, :books, :subscriptions, :developers, :categorizations, :essays
# Dummies to force column loads so query counts are clean.
def setup
@@ -33,6 +36,13 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
Reader.create :person_id => 0, :post_id => 0
end
+ def test_include?
+ person = Person.new
+ post = Post.new
+ person.posts << post
+ assert person.posts.include?(post)
+ end
+
def test_associate_existing
assert_queries(2) { posts(:thinking); people(:david) }
@@ -47,6 +57,16 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
assert posts(:thinking).reload.people(true).include?(people(:david))
end
+ 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
+
def test_associating_new
assert_queries(1) { posts(:thinking) }
new_person = nil # so block binding catches it
@@ -94,6 +114,24 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Ted")
end
+ def test_build_then_save_with_has_many_inverse
+ post = posts(:thinking)
+ person = post.people.build(:first_name => "Bob")
+ person.save
+ post.reload
+
+ assert post.people.include?(person)
+ end
+
+ 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 post.single_people.include?(person)
+ end
+
def test_delete_association
assert_queries(2){posts(:welcome);people(:michael); }
@@ -109,8 +147,10 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
end
def test_destroy_association
- assert_difference ["Person.count", "Reader.count"], -1 do
- posts(:welcome).people.destroy(people(:michael))
+ 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?
@@ -118,8 +158,10 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
end
def test_destroy_all
- assert_difference ["Person.count", "Reader.count"], -1 do
- posts(:welcome).people.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?
@@ -132,6 +174,137 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
end
end
+ 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_equal nil, reference.reload.job_id
+ ensure
+ Reference.make_comments = false
+ end
+
+ 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_equal nil, person.reload.comments
+ ensure
+ Reference.make_comments = false
+ end
+
+ 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
+
+ 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
+
+ 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
+
+ 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_equal nil, reference.reload.job_id
+ end
+ end
+
+ def test_update_counter_caches_on_delete
+ post = posts(:welcome)
+ tag = post.tags.create!(:name => 'doomed')
+
+ assert_difference ['post.reload.taggings_count', 'post.reload.tags_count'], -1 do
+ posts(:welcome).tags.delete(tag)
+ end
+ end
+
+ def test_update_counter_caches_on_delete_with_dependent_destroy
+ post = posts(:welcome)
+ tag = post.tags.create!(:name => 'doomed')
+ post.update_attribute(:tags_with_destroy_count, post.tags.count)
+
+ assert_difference ['post.reload.taggings_count', 'post.reload.tags_with_destroy_count'], -1 do
+ posts(:welcome).tags_with_destroy.delete(tag)
+ end
+ end
+
+ def test_update_counter_caches_on_delete_with_dependent_nullify
+ post = posts(:welcome)
+ tag = post.tags.create!(:name => 'doomed')
+ post.update_attribute(:tags_with_nullify_count, post.tags.count)
+
+ assert_no_difference 'post.reload.taggings_count' do
+ assert_difference 'post.reload.tags_with_nullify_count', -1 do
+ posts(:welcome).tags_with_nullify.delete(tag)
+ end
+ end
+ end
+
def test_replace_association
assert_queries(4){posts(:welcome);people(:david);people(:michael); posts(:welcome).people(true)}
@@ -326,12 +499,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
assert_equal 2, people(:michael).jobs.size
end
- def test_get_ids_for_belongs_to_source
- assert_sql(/DISTINCT/) { assert_equal [posts(:welcome).id, posts(:authorless).id].sort, people(:michael).post_ids.sort }
- end
-
- def test_get_ids_for_has_many_source
- assert_equal [comments(:eager_other_comment1).id], authors(:mary).comment_ids
+ def test_get_ids
+ assert_equal [posts(:welcome).id, posts(:authorless).id].sort, people(:michael).post_ids.sort
end
def test_get_ids_for_loaded_associations
@@ -392,6 +561,41 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
].each {|block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) }
end
+ 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.map(&:agents).flatten, people(:susan).agents_of_agents
+ end
+
+ 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
+
+ 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 author.named_categories(true).include?(category)
+ end
+
+ 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 author.named_categories(true).include?(category)
+ end
+
+ 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(true).empty?
+ end
+
def test_collection_singular_ids_getter_with_string_primary_keys
book = books(:awdr)
assert_equal 2, book.subscriber_ids.size
@@ -478,4 +682,88 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
post.people << people(:michael)
assert_equal readers + 1, post.readers.size
end
+
+ def test_has_many_through_with_default_scope_on_join_model
+ assert_equal posts(:welcome).comments.order('id').all, authors(:david).comments_on_first_posts
+ end
+
+ 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
+
+ def test_joining_has_many_through_with_uniq
+ 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
+
+ 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
+
+ def test_select_chosen_fields_only
+ author = authors(:david)
+ assert_equal ['body'], author.comments.select('comments.body').first.attributes.keys
+ end
+
+ def test_get_has_many_through_belongs_to_ids_with_conditions
+ assert_equal [categories(:general).id], authors(:mary).categories_like_general_ids
+ end
+
+ 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
+
+ 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
+
+ def test_create_with_conditions_hash_on_through_association
+ member = members(:groucho)
+ club = member.clubs.create!
+
+ assert_equal true, club.reload.membership.favourite
+ end
+
+ 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 post.author_addresses.include?(address)
+ post.author_addresses.delete(address)
+ assert post[:author_count].nil?
+ end
+
+ def test_interpolated_conditions
+ post = posts(:welcome)
+ assert !post.tags.empty?
+ assert_equal post.tags, post.interpolated_tags
+ assert_equal post.tags, post.interpolated_tags_2
+ end
+
+ def test_primary_key_option_on_source
+ post = posts(:welcome)
+ category = categories(:general)
+ categorization = 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
end
diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb
index 64449df8f5..c1dad5e246 100644
--- a/activerecord/test/cases/associations/has_one_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_associations_test.rb
@@ -2,9 +2,13 @@ require "cases/helper"
require 'models/developer'
require 'models/project'
require 'models/company'
+require 'models/ship'
+require 'models/pirate'
+require 'models/bulb'
class HasOneAssociationsTest < ActiveRecord::TestCase
- fixtures :accounts, :companies, :developers, :projects, :developers_projects
+ self.use_transactional_fixtures = false unless supports_savepoints?
+ fixtures :accounts, :companies, :developers, :projects, :developers_projects, :ships, :pirates
def setup
Account.destroyed_account_ids.clear
@@ -62,11 +66,6 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
assert_nothing_raised { company.account = company.account }
end
- def test_triple_equality
- assert Account === companies(:first_firm).account
- assert companies(:first_firm).account === Account
- end
-
def test_type_mismatch
assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).account = 1 }
assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).account = Project.find(1) }
@@ -91,18 +90,18 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
def test_nullification_on_association_change
firm = companies(:rails_core)
old_account_id = firm.account.id
- firm.account = Account.new
+ firm.account = Account.new(:credit_limit => 5)
# account is dependent with nullify, therefore its firm_id should be nil
assert_nil Account.find(old_account_id).firm_id
end
def test_association_change_calls_delete
- companies(:first_firm).deletable_account = Account.new
+ companies(:first_firm).deletable_account = Account.new(:credit_limit => 5)
assert_equal [], Account.destroyed_account_ids[companies(:first_firm).id]
end
def test_association_change_calls_destroy
- companies(:first_firm).account = Account.new
+ companies(:first_firm).account = Account.new(:credit_limit => 5)
assert_equal [companies(:first_firm).id], Account.destroyed_account_ids[companies(:first_firm).id]
end
@@ -116,35 +115,6 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
assert_equal company.account, account
end
- def test_assignment_without_replacement
- apple = Firm.create("name" => "Apple")
- citibank = Account.create("credit_limit" => 10)
- apple.account = citibank
- assert_equal apple.id, citibank.firm_id
-
- hsbc = apple.build_account({ :credit_limit => 20}, false)
- assert_equal apple.id, hsbc.firm_id
- hsbc.save
- assert_equal apple.id, citibank.firm_id
-
- nykredit = apple.create_account({ :credit_limit => 30}, false)
- assert_equal apple.id, nykredit.firm_id
- assert_equal apple.id, citibank.firm_id
- assert_equal apple.id, hsbc.firm_id
- end
-
- def test_assignment_without_replacement_on_create
- apple = Firm.create("name" => "Apple")
- citibank = Account.create("credit_limit" => 10)
- apple.account = citibank
- assert_equal apple.id, citibank.firm_id
-
- hsbc = apple.create_account({:credit_limit => 10}, false)
- assert_equal apple.id, hsbc.firm_id
- hsbc.save
- assert_equal apple.id, citibank.firm_id
- end
-
def test_dependence
num_accounts = Account.count
@@ -193,13 +163,18 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
assert_equal account, firm.account
end
- def test_build_association_twice_without_saving_affects_nothing
- count_of_account = Account.count
- firm = Firm.find(:first)
- firm.build_account("credit_limit" => 1000)
- firm.build_account("credit_limit" => 2000)
+ def test_build_and_create_should_not_happen_within_scope
+ pirate = pirates(:blackbeard)
+ original_scoped_methods = Bulb.scoped_methods.dup
- assert_equal count_of_account, Account.count
+ bulb = pirate.build_bulb
+ assert_equal original_scoped_methods, bulb.scoped_methods_after_initialize
+
+ bulb = pirate.create_bulb
+ assert_equal original_scoped_methods, bulb.scoped_methods_after_initialize
+
+ bulb = pirate.create_bulb!
+ assert_equal original_scoped_methods, bulb.scoped_methods_after_initialize
end
def test_create_association
@@ -208,25 +183,32 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
assert_equal account, firm.reload.account
end
- def test_build
- firm = Firm.new("name" => "GlobalMegaCorp")
- firm.save
+ def test_create_association_with_bang
+ firm = Firm.create(:name => "GlobalMegaCorp")
+ account = firm.create_account!(:credit_limit => 1000)
+ assert_equal account, firm.reload.account
+ end
- firm.account = account = Account.new("credit_limit" => 1000)
- assert_equal account, firm.account
- assert account.save
- assert_equal account, firm.account
+ def test_create_association_with_bang_failing
+ firm = Firm.create(:name => "GlobalMegaCorp")
+ assert_raise ActiveRecord::RecordInvalid do
+ firm.create_account!
+ end
+ account = firm.account
+ assert_not_nil account
+ account.credit_limit = 5
+ account.save
+ assert_equal account, firm.reload.account
end
- def test_failing_build_association
+ def test_build
firm = Firm.new("name" => "GlobalMegaCorp")
firm.save
- firm.account = account = Account.new
+ firm.account = account = Account.new("credit_limit" => 1000)
assert_equal account, firm.account
- assert !account.save
+ assert account.save
assert_equal account, firm.account
- assert_equal ["can't be empty"], account.errors["credit_limit"]
end
def test_create
@@ -330,4 +312,51 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
new_account = companies(:first_firm).build_account(:firm_name => 'Account')
assert_equal new_account.firm_name, "Account"
end
+
+ def test_creation_failure_without_dependent_option
+ pirate = pirates(:blackbeard)
+ orig_ship = pirate.ship
+
+ assert_equal ships(:black_pearl), orig_ship
+ new_ship = pirate.create_ship
+ assert_not_equal ships(:black_pearl), new_ship
+ assert_equal new_ship, pirate.ship
+ assert new_ship.new_record?
+ assert_nil orig_ship.pirate_id
+ assert !orig_ship.changed? # check it was saved
+ end
+
+ def test_creation_failure_with_dependent_option
+ pirate = pirates(:blackbeard).becomes(DestructivePirate)
+ orig_ship = pirate.dependent_ship
+
+ new_ship = pirate.create_dependent_ship
+ assert new_ship.new_record?
+ assert orig_ship.destroyed?
+ end
+
+ def test_replacement_failure_due_to_existing_record_should_raise_error
+ pirate = pirates(:blackbeard)
+ pirate.ship.name = nil
+
+ assert !pirate.ship.valid?
+ assert_raise(ActiveRecord::RecordNotSaved) do
+ pirate.ship = ships(:interceptor)
+ end
+ assert_equal ships(:black_pearl), pirate.ship
+ assert_equal pirate.id, pirate.ship.pirate_id
+ end
+
+ def test_replacement_failure_due_to_new_record_should_raise_error
+ pirate = pirates(:blackbeard)
+ new_ship = Ship.new
+
+ assert_raise(ActiveRecord::RecordNotSaved) do
+ pirate.ship = new_ship
+ end
+ assert_equal ships(:black_pearl), pirate.ship
+ assert_equal pirate.id, pirate.ship.pirate_id
+ assert_equal pirate.id, ships(:black_pearl).reload.pirate_id
+ assert_nil new_ship.pirate_id
+ end
end
diff --git a/activerecord/test/cases/associations/has_one_through_associations_test.rb b/activerecord/test/cases/associations/has_one_through_associations_test.rb
index fc56233ba8..9ba5549277 100644
--- a/activerecord/test/cases/associations/has_one_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_through_associations_test.rb
@@ -13,10 +13,12 @@ require 'models/category'
require 'models/author'
require 'models/essay'
require 'models/owner'
+require 'models/post'
+require 'models/comment'
class HasOneThroughAssociationsTest < ActiveRecord::TestCase
fixtures :member_types, :members, :clubs, :memberships, :sponsors, :organizations, :minivans,
- :dashboards, :speedometers, :categories, :authors, :essays, :owners
+ :dashboards, :speedometers, :authors, :posts, :comments, :categories, :essays, :owners
def setup
@member = members(:groucho)
@@ -26,10 +28,6 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
assert_equal clubs(:boring_club), @member.club
end
- def test_has_one_through_with_has_many
- assert_equal clubs(:moustache_club), @member.favourite_club
- end
-
def test_creating_association_creates_through_record
new_member = Member.create(:name => "Chris")
new_member.club = Club.create(:name => "LRUG")
@@ -89,6 +87,18 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
assert_not_nil assert_no_queries {members[0].sponsor_club}
end
+ def test_has_one_through_with_conditions_eager_loading
+ # conditions on the through table
+ assert_equal clubs(:moustache_club), Member.find(@member.id, :include => :favourite_club).favourite_club
+ memberships(:membership_of_favourite_club).update_attribute(:favourite, false)
+ assert_equal nil, Member.find(@member.id, :include => :favourite_club).reload.favourite_club
+
+ # conditions on the source table
+ assert_equal clubs(:moustache_club), Member.find(@member.id, :include => :hairy_club).hairy_club
+ clubs(:moustache_club).update_attribute(:name, "Association of Clean-Shaven Persons")
+ assert_equal nil, Member.find(@member.id, :include => :hairy_club).reload.hairy_club
+ end
+
def test_has_one_through_polymorphic_with_source_type
assert_equal members(:groucho), clubs(:moustache_club).sponsored_member
end
@@ -132,7 +142,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
def test_assigning_association_correctly_assigns_target
new_member = Member.create(:name => "Chris")
new_member.club = new_club = Club.create(:name => "LRUG")
- assert_equal new_club, new_member.club.target
+ assert_equal new_club, new_member.association(:club).target
end
def test_has_one_through_proxy_should_not_respond_to_private_methods
@@ -190,7 +200,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
MemberDetail.find(:all, :include => :member_type)
end
@new_detail = @member_details[0]
- assert @new_detail.loaded_member_type?
+ assert @new_detail.send(:association, :member_type).loaded?
assert_not_nil assert_no_queries { @new_detail.member_type }
end
@@ -253,4 +263,51 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
authors = Author.joins(:essay_category_2).where('categories.id' => categories(:general).id)
assert_equal authors(:david), authors.first
end
+
+ def test_has_one_through_with_default_scope_on_join_model
+ assert_equal posts(:welcome).comments.order('id').first, authors(:david).comment_on_first_post
+ end
+
+ def test_has_one_through_many_raises_exception
+ assert_raise(ActiveRecord::HasOneThroughCantAssociateThroughCollection) do
+ members(:groucho).club_through_many
+ end
+ end
+
+ def test_has_one_through_belongs_to_should_update_when_the_through_foreign_key_changes
+ minivan = minivans(:cool_first)
+
+ minivan.dashboard
+ proxy = minivan.send(:association_instance_get, :dashboard)
+
+ assert !proxy.stale_target?
+ assert_equal dashboards(:cool_first), minivan.dashboard
+
+ minivan.speedometer_id = speedometers(:second).id
+
+ assert proxy.stale_target?
+ assert_equal dashboards(:second), minivan.dashboard
+ end
+
+ def test_has_one_through_belongs_to_setting_belongs_to_foreign_key_after_nil_target_loaded
+ minivan = Minivan.new
+
+ minivan.dashboard
+ proxy = minivan.send(:association_instance_get, :dashboard)
+
+ minivan.speedometer_id = speedometers(:second).id
+
+ assert proxy.stale_target?
+ assert_equal dashboards(:second), minivan.dashboard
+ end
+
+ def test_assigning_has_one_through_belongs_to_with_new_record_owner
+ minivan = Minivan.new
+ dashboard = dashboards(:cool_first)
+
+ minivan.dashboard = dashboard
+
+ assert_equal dashboard, minivan.dashboard
+ assert_equal dashboard, minivan.speedometer.dashboard
+ end
end
diff --git a/activerecord/test/cases/associations/identity_map_test.rb b/activerecord/test/cases/associations/identity_map_test.rb
new file mode 100644
index 0000000000..9b8635774c
--- /dev/null
+++ b/activerecord/test/cases/associations/identity_map_test.rb
@@ -0,0 +1,137 @@
+require "cases/helper"
+require 'models/author'
+require 'models/post'
+
+if ActiveRecord::IdentityMap.enabled?
+class InverseHasManyIdentityMapTest < ActiveRecord::TestCase
+ fixtures :authors, :posts
+
+ def test_parent_instance_should_be_shared_with_every_child_on_find
+ m = Author.first
+ is = m.posts
+ is.each do |i|
+ assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance"
+ i.author.name = 'Mungo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to child-owned instance"
+ end
+ end
+
+ def test_parent_instance_should_be_shared_with_eager_loaded_children
+ m = Author.find(:first, :include => :posts)
+ is = m.posts
+ is.each do |i|
+ assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance"
+ i.author.name = 'Mungo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to child-owned instance"
+ end
+
+ m = Author.find(:first, :include => :posts, :order => 'posts.id')
+ is = m.posts
+ is.each do |i|
+ assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance"
+ i.author.name = 'Mungo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to child-owned instance"
+ end
+ end
+
+ def test_parent_instance_should_be_shared_with_newly_built_child
+ m = Author.first
+ i = m.posts.build(:title => 'Industrial Revolution Re-enactment', :body => 'Lorem ipsum')
+ assert_not_nil i.author
+ assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance"
+ i.author.name = 'Mungo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to just-built-child-owned instance"
+ end
+
+ def test_parent_instance_should_be_shared_with_newly_block_style_built_child
+ m = Author.first
+ i = m.posts.build {|ii| ii.title = 'Industrial Revolution Re-enactment'; ii.body = 'Lorem ipsum'}
+ assert_not_nil i.title, "Child attributes supplied to build via blocks should be populated"
+ assert_not_nil i.author
+ assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance"
+ i.author.name = 'Mungo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to just-built-child-owned instance"
+ end
+
+ def test_parent_instance_should_be_shared_with_newly_created_child
+ m = Author.first
+ i = m.posts.create(:title => 'Industrial Revolution Re-enactment', :body => 'Lorem ipsum')
+ assert_not_nil i.author
+ assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance"
+ i.author.name = 'Mungo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to newly-created-child-owned instance"
+ end
+
+ def test_parent_instance_should_be_shared_with_newly_created_via_bang_method_child
+ m = Author.first
+ i = m.posts.create!(:title => 'Industrial Revolution Re-enactment', :body => 'Lorem ipsum')
+ assert_not_nil i.author
+ assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance"
+ i.author.name = 'Mungo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to newly-created-child-owned instance"
+ end
+
+ def test_parent_instance_should_be_shared_with_newly_block_style_created_child
+ m = Author.first
+ i = m.posts.create {|ii| ii.title = 'Industrial Revolution Re-enactment'; ii.body = 'Lorem ipsum'}
+ assert_not_nil i.title, "Child attributes supplied to create via blocks should be populated"
+ assert_not_nil i.author
+ assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance"
+ i.author.name = 'Mungo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to newly-created-child-owned instance"
+ end
+
+ def test_parent_instance_should_be_shared_with_poked_in_child
+ m = Author.first
+ i = Post.create(:title => 'Industrial Revolution Re-enactment', :body => 'Lorem ipsum')
+ m.posts << i
+ assert_not_nil i.author
+ assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance"
+ i.author.name = 'Mungo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to newly-created-child-owned instance"
+ end
+
+ def test_parent_instance_should_be_shared_with_replaced_via_accessor_children
+ m = Author.first
+ i = Post.new(:title => 'Industrial Revolution Re-enactment', :body => 'Lorem ipsum')
+ m.posts = [i]
+ assert_same m, i.author
+ assert_not_nil i.author
+ assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance"
+ i.author.name = 'Mungo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to replaced-child-owned instance"
+ end
+
+ def test_parent_instance_should_be_shared_with_replaced_via_method_children
+ m = Author.first
+ i = Post.new(:title => 'Industrial Revolution Re-enactment', :body => 'Lorem ipsum')
+ m.posts = [i]
+ assert_not_nil i.author
+ assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance"
+ i.author.name = 'Mungo'
+ assert_equal m.name, i.author.name, "Name of man should be the same after changes to replaced-child-owned instance"
+ end
+end
+end
diff --git a/activerecord/test/cases/associations/inner_join_association_test.rb b/activerecord/test/cases/associations/inner_join_association_test.rb
index 780eabc443..e2228228a3 100644
--- a/activerecord/test/cases/associations/inner_join_association_test.rb
+++ b/activerecord/test/cases/associations/inner_join_association_test.rb
@@ -4,6 +4,7 @@ require 'models/comment'
require 'models/author'
require 'models/category'
require 'models/categorization'
+require 'models/person'
require 'models/tagging'
require 'models/tag'
@@ -16,6 +17,13 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase
assert_equal authors(:david), result.first
end
+ def test_construct_finder_sql_does_not_table_name_collide_on_duplicate_associations
+ assert_nothing_raised do
+ sql = Person.joins(:agents => {:agents => :agents}).joins(:agents => {:agents => {:primary_contact => :agents}}).to_sql
+ assert_match(/agents_people_4/i, sql)
+ end
+ end
+
def test_construct_finder_sql_ignores_empty_joins_hash
sql = Author.joins({}).to_sql
assert_no_match(/JOIN/i, sql)
@@ -65,21 +73,21 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase
authors_with_welcoming_post_titles = Author.calculate(:count, 'authors.id', :joins => :posts, :distinct => true, :conditions => "posts.title like 'Welcome%'")
assert_equal real_count, authors_with_welcoming_post_titles, "inner join and conditions should have only returned authors posting titles starting with 'Welcome'"
end
-
+
def test_find_with_sti_join
scope = Post.joins(:special_comments).where(:id => posts(:sti_comments).id)
-
+
# The join should match SpecialComment and its subclasses only
assert scope.where("comments.type" => "Comment").empty?
assert !scope.where("comments.type" => "SpecialComment").empty?
assert !scope.where("comments.type" => "SubSpecialComment").empty?
end
-
+
def test_find_with_conditions_on_reflection
assert !posts(:welcome).comments.empty?
assert Post.joins(:nonexistant_comments).where(:id => posts(:welcome).id).empty? # [sic!]
end
-
+
def test_find_with_conditions_on_through_reflection
assert !posts(:welcome).tags.empty?
assert Post.joins(:misc_tags).where(:id => posts(:welcome).id).empty?
diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb
index 0491b2d1fa..76282213d8 100644
--- a/activerecord/test/cases/associations/inverse_associations_test.rb
+++ b/activerecord/test/cases/associations/inverse_associations_test.rb
@@ -114,7 +114,7 @@ class InverseHasOneTests < ActiveRecord::TestCase
end
def test_parent_instance_should_be_shared_with_newly_built_child
- m = men(:gordon)
+ m = Man.find(:first)
f = m.build_face(:description => 'haunted')
assert_not_nil f.man
assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
@@ -125,7 +125,7 @@ class InverseHasOneTests < ActiveRecord::TestCase
end
def test_parent_instance_should_be_shared_with_newly_created_child
- m = men(:gordon)
+ m = Man.find(:first)
f = m.create_face(:description => 'haunted')
assert_not_nil f.man
assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
@@ -137,40 +137,7 @@ class InverseHasOneTests < ActiveRecord::TestCase
def test_parent_instance_should_be_shared_with_newly_created_child_via_bang_method
m = Man.find(:first)
- f = m.face.create!(:description => 'haunted')
- assert_not_nil f.man
- assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
- m.name = 'Bongo'
- assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance"
- f.man.name = 'Mungo'
- assert_equal m.name, f.man.name, "Name of man should be the same after changes to newly-created-child-owned instance"
- end
-
- def test_parent_instance_should_be_shared_with_newly_built_child_when_we_dont_replace_existing
- m = Man.find(:first)
- f = m.build_face({:description => 'haunted'}, false)
- assert_not_nil f.man
- assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
- m.name = 'Bongo'
- assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance"
- f.man.name = 'Mungo'
- assert_equal m.name, f.man.name, "Name of man should be the same after changes to just-built-child-owned instance"
- end
-
- def test_parent_instance_should_be_shared_with_newly_created_child_when_we_dont_replace_existing
- m = Man.find(:first)
- f = m.create_face({:description => 'haunted'}, false)
- assert_not_nil f.man
- assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
- m.name = 'Bongo'
- assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance"
- f.man.name = 'Mungo'
- assert_equal m.name, f.man.name, "Name of man should be the same after changes to newly-created-child-owned instance"
- end
-
- def test_parent_instance_should_be_shared_with_newly_created_child_via_bang_method_when_we_dont_replace_existing
- m = Man.find(:first)
- f = m.face.create!({:description => 'haunted'}, false)
+ f = m.create_face!(:description => 'haunted')
assert_not_nil f.man
assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
m.name = 'Bongo'
@@ -191,30 +158,6 @@ class InverseHasOneTests < ActiveRecord::TestCase
assert_equal m.name, f.man.name, "Name of man should be the same after changes to replaced-child-owned instance"
end
- def test_parent_instance_should_be_shared_with_replaced_via_method_child
- m = Man.find(:first)
- f = Face.new(:description => 'haunted')
- m.face.replace(f)
- assert_not_nil f.man
- assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
- m.name = 'Bongo'
- assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance"
- f.man.name = 'Mungo'
- assert_equal m.name, f.man.name, "Name of man should be the same after changes to replaced-child-owned instance"
- end
-
- def test_parent_instance_should_be_shared_with_replaced_via_method_child_when_we_dont_replace_existing
- m = Man.find(:first)
- f = Face.new(:description => 'haunted')
- m.face.replace(f, false)
- assert_not_nil f.man
- assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
- m.name = 'Bongo'
- assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance"
- f.man.name = 'Mungo'
- assert_equal m.name, f.man.name, "Name of man should be the same after changes to replaced-child-owned instance"
- end
-
def test_trying_to_use_inverses_that_dont_exist_should_raise_an_error
assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Man.find(:first).dirty_face }
end
@@ -257,17 +200,6 @@ class InverseHasManyTests < ActiveRecord::TestCase
end
end
- def test_parent_instance_should_be_shared_with_newly_built_child
- m = men(:gordon)
- i = m.interests.build(:topic => 'Industrial Revolution Re-enactment')
- assert_not_nil i.man
- assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance"
- m.name = 'Bongo'
- assert_equal m.name, i.man.name, "Name of man should be the same after changes to parent instance"
- i.man.name = 'Mungo'
- assert_equal m.name, i.man.name, "Name of man should be the same after changes to just-built-child-owned instance"
- end
-
def test_parent_instance_should_be_shared_with_newly_block_style_built_child
m = Man.find(:first)
i = m.interests.build {|ii| ii.topic = 'Industrial Revolution Re-enactment'}
@@ -280,17 +212,6 @@ class InverseHasManyTests < ActiveRecord::TestCase
assert_equal m.name, i.man.name, "Name of man should be the same after changes to just-built-child-owned instance"
end
- def test_parent_instance_should_be_shared_with_newly_created_child
- m = men(:gordon)
- i = m.interests.create(:topic => 'Industrial Revolution Re-enactment')
- assert_not_nil i.man
- assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance"
- m.name = 'Bongo'
- assert_equal m.name, i.man.name, "Name of man should be the same after changes to parent instance"
- i.man.name = 'Mungo'
- assert_equal m.name, i.man.name, "Name of man should be the same after changes to newly-created-child-owned instance"
- end
-
def test_parent_instance_should_be_shared_with_newly_created_via_bang_method_child
m = Man.find(:first)
i = m.interests.create!(:topic => 'Industrial Revolution Re-enactment')
@@ -338,18 +259,6 @@ class InverseHasManyTests < ActiveRecord::TestCase
assert_equal m.name, i.man.name, "Name of man should be the same after changes to replaced-child-owned instance"
end
- def test_parent_instance_should_be_shared_with_replaced_via_method_children
- m = Man.find(:first)
- i = Interest.new(:topic => 'Industrial Revolution Re-enactment')
- m.interests.replace([i])
- assert_not_nil i.man
- assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance"
- m.name = 'Bongo'
- assert_equal m.name, i.man.name, "Name of man should be the same after changes to parent instance"
- i.man.name = 'Mungo'
- assert_equal m.name, i.man.name, "Name of man should be the same after changes to replaced-child-owned instance"
- end
-
def test_trying_to_use_inverses_that_dont_exist_should_raise_an_error
assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Man.find(:first).secret_interests }
end
@@ -433,19 +342,6 @@ class InverseBelongsToTests < ActiveRecord::TestCase
assert_equal f.description, m.face.description, "Description of face should be the same after changes to replaced-parent-owned instance"
end
- def test_child_instance_should_be_shared_with_replaced_via_method_parent
- f = faces(:trusting)
- assert_not_nil f.man
- m = Man.new(:name => 'Charles')
- f.man.replace(m)
- assert_not_nil m.face
- assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance"
- f.description = 'gormless'
- assert_equal f.description, m.face.description, "Description of face should be the same after changes to child instance"
- m.face.description = 'pleasing'
- assert_equal f.description, m.face.description, "Description of face should be the same after changes to replaced-parent-owned instance"
- end
-
def test_trying_to_use_inverses_that_dont_exist_should_raise_an_error
assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Face.find(:first).horrible_man }
end
@@ -501,7 +397,7 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase
new_man = Man.new
assert_not_nil face.polymorphic_man
- face.polymorphic_man.replace(new_man)
+ face.polymorphic_man = new_man
assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same before changes to parent instance"
face.description = 'Bongo'
diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb
index 2aac95a25d..543eff7d8b 100644
--- a/activerecord/test/cases/associations/join_model_test.rb
+++ b/activerecord/test/cases/associations/join_model_test.rb
@@ -13,7 +13,8 @@ require 'models/book'
require 'models/citation'
class AssociationsJoinModelTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+ self.use_transactional_fixtures = false unless supports_savepoints?
+
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
@@ -85,16 +86,9 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
end
- 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
+ assert_nothing_raised(NoMethodError) { tag.author_id }
end
def test_polymorphic_has_many_going_through_join_model_with_custom_foreign_key
@@ -159,7 +153,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
def test_create_polymorphic_has_one_with_scope
old_count = Tagging.count
- tagging = posts(:welcome).tagging.create(:tag => tags(:misc))
+ tagging = posts(:welcome).create_tagging(:tag => tags(:misc))
assert_equal "Post", tagging.taggable_type
assert_equal old_count+1, Tagging.count
end
@@ -220,7 +214,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_has_many_with_piggyback
- assert_equal "2", categories(:sti_test).authors.first.post_id.to_s
+ assert_equal "2", categories(:sti_test).authors_with_select.first.post_id.to_s
end
def test_include_has_many_through
@@ -298,6 +292,22 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
assert_equal [authors(:mary)], posts(:authorless).authors
end
+ 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), authors(:bob)], posts(:thinking).authors_using_custom_pk.order(:id)
+ end
+
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
@@ -324,11 +334,16 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_has_many_polymorphic
- assert_raise ActiveRecord::HasManyThroughAssociationPolymorphicError do
- assert_equal posts(:welcome, :thinking), tags(:general).taggables
+ assert_raise ActiveRecord::HasManyThroughAssociationPolymorphicSourceError do
+ tags(:general).taggables
+ end
+
+ assert_raise ActiveRecord::HasManyThroughAssociationPolymorphicThroughError do
+ taggings(:welcome_general).things
end
+
assert_raise ActiveRecord::EagerLoadPolymorphicError do
- assert_equal posts(:welcome, :thinking), tags(:general).taggings.find(:all, :include => :taggable, :conditions => 'bogus_table.column = 1')
+ tags(:general).taggings.find(:all, :include => :taggable, :conditions => 'bogus_table.column = 1')
end
end
@@ -488,6 +503,10 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
assert_nothing_raised { vertices(:vertex_1).sinks << vertices(:vertex_5) }
end
+ def test_add_to_join_table_with_no_id
+ assert_nothing_raised { vertices(:vertex_1).sinks << vertices(:vertex_5) }
+ end
+
def test_has_many_through_collection_size_doesnt_load_target_if_not_loaded
author = authors(:david)
assert_equal 10, author.comments.size
@@ -496,7 +515,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
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)
+ author.stubs(:_read_attribute).with('comments_count').returns(100)
assert_equal 100, author.comments.size
assert !author.comments.loaded?
end
diff --git a/activerecord/test/cases/associations/nested_through_associations_test.rb b/activerecord/test/cases/associations/nested_through_associations_test.rb
index db7c8b6c45..a4ac69782a 100644
--- a/activerecord/test/cases/associations/nested_through_associations_test.rb
+++ b/activerecord/test/cases/associations/nested_through_associations_test.rb
@@ -51,9 +51,19 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
# Through: has_many
def test_has_many_through_has_many_with_has_many_through_source_reflection
general = tags(:general)
-
assert_equal [general, general], authors(:david).tags
+ end
+
+ def test_has_many_through_has_many_with_has_many_through_source_reflection_preload
+ authors = assert_queries(5) { Author.includes(:tags).to_a }
+ general = tags(:general)
+
+ assert_no_queries do
+ assert_equal [general, general], authors.first.tags
+ end
+ end
+ def test_has_many_through_has_many_with_has_many_through_source_reflection_preload_via_joins
assert_includes_and_joins_equal(
Author.where('tags.id' => tags(:general).id),
[authors(:david)], :tags
@@ -62,11 +72,6 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
# This ensures that the polymorphism of taggings is being observed correctly
authors = Author.joins(:tags).where('taggings.taggable_type' => 'FakeModel')
assert authors.empty?
-
- authors = assert_queries(5) { Author.includes(:tags).to_a }
- assert_no_queries do
- assert_equal [general, general], authors.first.tags
- end
end
# has_many through
@@ -74,60 +79,69 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
# Through: has_many through
def test_has_many_through_has_many_through_with_has_many_source_reflection
luke, david = subscribers(:first), subscribers(:second)
+ assert_equal [luke, david, david], authors(:david).subscribers.order('subscribers.nick')
+ end
- author = authors(:david)
- assert_equal [luke, david, david], author.subscribers.order('subscribers.nick')
+ def test_has_many_through_has_many_through_with_has_many_source_reflection_preload
+ luke, david = subscribers(:first), subscribers(:second)
+ authors = assert_queries(4) { Author.includes(:subscribers).to_a }
+ assert_no_queries do
+ assert_equal [luke, david, david], authors.first.subscribers.sort_by(&:nick)
+ end
+ end
+ def test_has_many_through_has_many_through_with_has_many_source_reflection_preload_via_joins
# All authors with subscribers where one of the subscribers' nick is 'alterself'
assert_includes_and_joins_equal(
Author.where('subscribers.nick' => 'alterself'),
[authors(:david)], :subscribers
)
-
- authors = assert_queries(4) { Author.includes(:subscribers).to_a }
- assert_no_queries do
- assert_equal [luke, david, david], authors.first.subscribers.sort_by(&:nick)
- end
end
# has_many through
# Source: has_one through
# Through: has_one
def test_has_many_through_has_one_with_has_one_through_source_reflection
- founding = member_types(:founding)
-
- assert_equal [founding], members(:groucho).nested_member_types
-
- assert_includes_and_joins_equal(
- Member.where('member_types.id' => founding.id),
- [members(:groucho)], :nested_member_types
- )
+ assert_equal [member_types(:founding)], members(:groucho).nested_member_types
+ end
+ def test_has_many_through_has_one_with_has_one_through_source_reflection_preload
members = assert_queries(4) { Member.includes(:nested_member_types).to_a }
+ founding = member_types(:founding)
assert_no_queries do
assert_equal [founding], members.first.nested_member_types
end
end
+ def test_has_many_through_has_one_with_has_one_through_source_reflection_preload_via_joins
+ assert_includes_and_joins_equal(
+ Member.where('member_types.id' => member_types(:founding).id),
+ [members(:groucho)], :nested_member_types
+ )
+ end
+
# has_many through
# Source: has_one
# Through: has_one through
def test_has_many_through_has_one_through_with_has_one_source_reflection
- mustache = sponsors(:moustache_club_sponsor_for_groucho)
-
- assert_equal [mustache], members(:groucho).nested_sponsors
-
- assert_includes_and_joins_equal(
- Member.where('sponsors.id' => mustache.id),
- [members(:groucho)], :nested_sponsors
- )
+ assert_equal [sponsors(:moustache_club_sponsor_for_groucho)], members(:groucho).nested_sponsors
+ end
+ def test_has_many_through_has_one_through_with_has_one_source_reflection_preload
members = assert_queries(4) { Member.includes(:nested_sponsors).to_a }
+ mustache = sponsors(:moustache_club_sponsor_for_groucho)
assert_no_queries do
assert_equal [mustache], members.first.nested_sponsors
end
end
+ def test_has_many_through_has_one_through_with_has_one_source_reflection_preload_via_joins
+ assert_includes_and_joins_equal(
+ Member.where('sponsors.id' => sponsors(:moustache_club_sponsor_for_groucho).id),
+ [members(:groucho)], :nested_sponsors
+ )
+ end
+
# has_many through
# Source: has_many through
# Through: has_one
@@ -136,7 +150,18 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
assert_equal [groucho_details, other_details],
members(:groucho).organization_member_details.order('member_details.id')
+ end
+
+ def test_has_many_through_has_one_with_has_many_through_source_reflection_preload
+ members = assert_queries(4) { Member.includes(:organization_member_details).to_a.sort_by(&:id) }
+ groucho_details, other_details = member_details(:groucho), member_details(:some_other_guy)
+
+ assert_no_queries do
+ assert_equal [groucho_details, other_details], members.first.organization_member_details.sort_by(&:id)
+ end
+ end
+ def test_has_many_through_has_one_with_has_many_through_source_reflection_preload_via_joins
assert_includes_and_joins_equal(
Member.where('member_details.id' => member_details(:groucho).id).order('member_details.id'),
[members(:groucho), members(:some_other_guy)], :organization_member_details
@@ -145,11 +170,6 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
members = Member.joins(:organization_member_details).
where('member_details.id' => 9)
assert members.empty?
-
- members = assert_queries(4) { Member.includes(:organization_member_details).to_a.sort_by(&:id) }
- assert_no_queries do
- assert_equal [groucho_details, other_details], members.first.organization_member_details.sort_by(&:id)
- end
end
# has_many through
@@ -160,20 +180,26 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
assert_equal [groucho_details, other_details],
members(:groucho).organization_member_details_2.order('member_details.id')
+ end
+
+ def test_has_many_through_has_one_through_with_has_many_source_reflection_preload
+ members = assert_queries(4) { Member.includes(:organization_member_details_2).to_a.sort_by(&:id) }
+ groucho_details, other_details = member_details(:groucho), member_details(:some_other_guy)
+ assert_no_queries do
+ assert_equal [groucho_details, other_details], members.first.organization_member_details_2.sort_by(&:id)
+ end
+ end
+
+ def test_has_many_through_has_one_through_with_has_many_source_reflection_preload_via_joins
assert_includes_and_joins_equal(
- Member.where('member_details.id' => groucho_details.id).order('member_details.id'),
+ Member.where('member_details.id' => member_details(:groucho).id).order('member_details.id'),
[members(:groucho), members(:some_other_guy)], :organization_member_details_2
)
members = Member.joins(:organization_member_details_2).
where('member_details.id' => 9)
assert members.empty?
-
- members = assert_queries(4) { Member.includes(:organization_member_details_2).to_a.sort_by(&:id) }
- assert_no_queries do
- assert_equal [groucho_details, other_details], members.first.organization_member_details_2.sort_by(&:id)
- end
end
# has_many through
@@ -183,18 +209,24 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
general, cooking = categories(:general), categories(:cooking)
assert_equal [general, cooking], authors(:bob).post_categories.order('categories.id')
+ end
- assert_includes_and_joins_equal(
- Author.where('categories.id' => cooking.id),
- [authors(:bob)], :post_categories
- )
-
+ def test_has_many_through_has_many_with_has_and_belongs_to_many_source_reflection_preload
authors = assert_queries(3) { Author.includes(:post_categories).to_a.sort_by(&:id) }
+ general, cooking = categories(:general), categories(:cooking)
+
assert_no_queries do
assert_equal [general, cooking], authors[2].post_categories.sort_by(&:id)
end
end
+ def test_has_many_through_has_many_with_has_and_belongs_to_many_source_reflection_preload_via_joins
+ assert_includes_and_joins_equal(
+ Author.where('categories.id' => categories(:cooking).id),
+ [authors(:bob)], :post_categories
+ )
+ end
+
# has_many through
# Source: has_many
# Through: has_and_belongs_to_many
@@ -202,18 +234,24 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
greetings, more = comments(:greetings), comments(:more_greetings)
assert_equal [greetings, more], categories(:technology).post_comments.order('comments.id')
+ end
- assert_includes_and_joins_equal(
- Category.where('comments.id' => more.id).order('comments.id'),
- [categories(:general), categories(:technology)], :post_comments
- )
-
+ def test_has_many_through_has_and_belongs_to_many_with_has_many_source_reflection_preload
categories = assert_queries(3) { Category.includes(:post_comments).to_a.sort_by(&:id) }
+ greetings, more = comments(:greetings), comments(:more_greetings)
+
assert_no_queries do
assert_equal [greetings, more], categories[1].post_comments.sort_by(&:id)
end
end
+ def test_has_many_through_has_and_belongs_to_many_with_has_many_source_reflection_preload_via_joins
+ assert_includes_and_joins_equal(
+ Category.where('comments.id' => comments(:more_greetings).id).order('comments.id'),
+ [categories(:general), categories(:technology)], :post_comments
+ )
+ end
+
# has_many through
# Source: has_many through a habtm
# Through: has_many through
@@ -221,35 +259,45 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
greetings, more = comments(:greetings), comments(:more_greetings)
assert_equal [greetings, more], authors(:bob).category_post_comments.order('comments.id')
+ end
- assert_includes_and_joins_equal(
- Author.where('comments.id' => comments(:does_it_hurt).id).order('comments.id'),
- [authors(:david), authors(:mary)], :category_post_comments
- )
-
+ def test_has_many_through_has_many_with_has_many_through_habtm_source_reflection_preload
authors = assert_queries(5) { Author.includes(:category_post_comments).to_a.sort_by(&:id) }
+ greetings, more = comments(:greetings), comments(:more_greetings)
+
assert_no_queries do
assert_equal [greetings, more], authors[2].category_post_comments.sort_by(&:id)
end
end
+ def test_has_many_through_has_many_with_has_many_through_habtm_source_reflection_preload_via_joins
+ assert_includes_and_joins_equal(
+ Author.where('comments.id' => comments(:does_it_hurt).id).order('comments.id'),
+ [authors(:david), authors(:mary)], :category_post_comments
+ )
+ end
+
# has_many through
# Source: belongs_to
# Through: has_many through
def test_has_many_through_has_many_through_with_belongs_to_source_reflection
+ assert_equal [tags(:general), tags(:general)], authors(:david).tagging_tags
+ end
+
+ def test_has_many_through_has_many_through_with_belongs_to_source_reflection_preload
+ authors = assert_queries(5) { Author.includes(:tagging_tags).to_a }
general = tags(:general)
- assert_equal [general, general], authors(:david).tagging_tags
+ assert_no_queries do
+ assert_equal [general, general], authors.first.tagging_tags
+ end
+ end
+ def test_has_many_through_has_many_through_with_belongs_to_source_reflection_preload_via_joins
assert_includes_and_joins_equal(
Author.where('tags.id' => tags(:general).id),
[authors(:david)], :tagging_tags
)
-
- authors = assert_queries(5) { Author.includes(:tagging_tags).to_a }
- assert_no_queries do
- assert_equal [general, general], authors.first.tagging_tags
- end
end
# has_many through
@@ -260,54 +308,68 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
assert_equal [welcome_general, thinking_general],
categorizations(:david_welcome_general).post_taggings.order('taggings.id')
+ end
- assert_includes_and_joins_equal(
- Categorization.where('taggings.id' => welcome_general.id).order('taggings.id'),
- [categorizations(:david_welcome_general)], :post_taggings
- )
-
+ def test_has_many_through_belongs_to_with_has_many_through_source_reflection_preload
categorizations = assert_queries(4) { Categorization.includes(:post_taggings).to_a.sort_by(&:id) }
+ welcome_general, thinking_general = taggings(:welcome_general), taggings(:thinking_general)
+
assert_no_queries do
assert_equal [welcome_general, thinking_general], categorizations.first.post_taggings.sort_by(&:id)
end
end
+ def test_has_many_through_belongs_to_with_has_many_through_source_reflection_preload_via_joins
+ assert_includes_and_joins_equal(
+ Categorization.where('taggings.id' => taggings(:welcome_general).id).order('taggings.id'),
+ [categorizations(:david_welcome_general)], :post_taggings
+ )
+ end
+
# has_one through
# Source: has_one through
# Through: has_one
def test_has_one_through_has_one_with_has_one_through_source_reflection
+ assert_equal member_types(:founding), members(:groucho).nested_member_type
+ end
+
+ def test_has_one_through_has_one_with_has_one_through_source_reflection_preload
+ members = assert_queries(4) { Member.includes(:nested_member_type).to_a.sort_by(&:id) }
founding = member_types(:founding)
- assert_equal founding, members(:groucho).nested_member_type
+ assert_no_queries do
+ assert_equal founding, members.first.nested_member_type
+ end
+ end
+ def test_has_one_through_has_one_with_has_one_through_source_reflection_preload_via_joins
assert_includes_and_joins_equal(
- Member.where('member_types.id' => founding.id),
+ Member.where('member_types.id' => member_types(:founding).id),
[members(:groucho)], :nested_member_type
)
-
- members = assert_queries(4) { Member.includes(:nested_member_type).to_a.sort_by(&:id) }
- assert_no_queries do
- assert_equal founding, members.first.nested_member_type
- end
end
# has_one through
# Source: belongs_to
# Through: has_one through
def test_has_one_through_has_one_through_with_belongs_to_source_reflection
+ assert_equal categories(:general), members(:groucho).club_category
+ end
+
+ def test_has_one_through_has_one_through_with_belongs_to_source_reflection_preload
+ members = assert_queries(4) { Member.includes(:club_category).to_a.sort_by(&:id) }
general = categories(:general)
- assert_equal general, members(:groucho).club_category
+ assert_no_queries do
+ assert_equal general, members.first.club_category
+ end
+ end
+ def test_has_one_through_has_one_through_with_belongs_to_source_reflection_preload_via_joins
assert_includes_and_joins_equal(
Member.where('categories.id' => categories(:technology).id),
[members(:blarpy_winkup)], :club_category
)
-
- members = assert_queries(4) { Member.includes(:club_category).to_a.sort_by(&:id) }
- assert_no_queries do
- assert_equal general, members.first.club_category
- end
end
def test_distinct_has_many_through_a_has_many_through_association_on_source_reflection
@@ -406,41 +468,49 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
end
def test_nested_has_many_through_with_conditions_on_through_associations
- blue, bob = tags(:blue), authors(:bob)
-
- assert_equal [blue], bob.misc_post_first_blue_tags
-
- # Pointless condition to force single-query loading
- assert_includes_and_joins_equal(
- Author.where('tags.id = tags.id'),
- [bob], :misc_post_first_blue_tags
- )
+ assert_equal [tags(:blue)], authors(:bob).misc_post_first_blue_tags
+ end
+ def test_nested_has_many_through_with_conditions_on_through_associations_preload
assert Author.where('tags.id' => 100).joins(:misc_post_first_blue_tags).empty?
authors = assert_queries(3) { Author.includes(:misc_post_first_blue_tags).to_a.sort_by(&:id) }
+ blue = tags(:blue)
+
assert_no_queries do
assert_equal [blue], authors[2].misc_post_first_blue_tags
end
end
- def test_nested_has_many_through_with_conditions_on_source_associations
- blue, bob = tags(:blue), authors(:bob)
-
- assert_equal [blue], bob.misc_post_first_blue_tags_2
-
+ def test_nested_has_many_through_with_conditions_on_through_associations_preload_via_joins
# Pointless condition to force single-query loading
assert_includes_and_joins_equal(
Author.where('tags.id = tags.id'),
- [bob], :misc_post_first_blue_tags_2
+ [authors(:bob)], :misc_post_first_blue_tags
)
+ end
+
+ def test_nested_has_many_through_with_conditions_on_source_associations
+ assert_equal [tags(:blue)], authors(:bob).misc_post_first_blue_tags_2
+ end
+ def test_nested_has_many_through_with_conditions_on_source_associations_preload
authors = assert_queries(4) { Author.includes(:misc_post_first_blue_tags_2).to_a.sort_by(&:id) }
+ blue = tags(:blue)
+
assert_no_queries do
assert_equal [blue], authors[2].misc_post_first_blue_tags_2
end
end
+ def test_nested_has_many_through_with_conditions_on_source_associations_preload_via_joins
+ # Pointless condition to force single-query loading
+ assert_includes_and_joins_equal(
+ Author.where('tags.id = tags.id'),
+ [authors(:bob)], :misc_post_first_blue_tags_2
+ )
+ end
+
def test_nested_has_many_through_with_foreign_key_option_on_the_source_reflection_through_reflection
assert_equal [categories(:general)], organizations(:nsa).author_essay_categories