aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test/cases
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/test/cases')
-rw-r--r--activerecord/test/cases/associations/cascaded_eager_loading_test.rb18
-rw-r--r--activerecord/test/cases/associations/eager_test.rb4
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb6
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb25
-rw-r--r--activerecord/test/cases/associations/has_one_through_associations_test.rb26
-rw-r--r--activerecord/test/cases/associations/join_model_test.rb10
-rw-r--r--activerecord/test/cases/associations/nested_through_associations_test.rb467
-rw-r--r--activerecord/test/cases/batches_test.rb2
-rw-r--r--activerecord/test/cases/finder_test.rb6
-rw-r--r--activerecord/test/cases/json_serialization_test.rb8
-rw-r--r--activerecord/test/cases/reflection_test.rb64
-rw-r--r--activerecord/test/cases/relation_scoping_test.rb2
-rw-r--r--activerecord/test/cases/relations_test.rb38
13 files changed, 626 insertions, 50 deletions
diff --git a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
index 271bb92ee8..81e99036af 100644
--- a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
+++ b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
@@ -14,17 +14,17 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
def test_eager_association_loading_with_cascaded_two_levels
authors = Author.find(:all, :include=>{:posts=>:comments}, :order=>"authors.id")
- assert_equal 2, authors.size
+ assert_equal 3, authors.size
assert_equal 5, authors[0].posts.size
- assert_equal 1, authors[1].posts.size
+ assert_equal 3, authors[1].posts.size
assert_equal 10, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
end
def test_eager_association_loading_with_cascaded_two_levels_and_one_level
authors = Author.find(:all, :include=>[{:posts=>:comments}, :categorizations], :order=>"authors.id")
- assert_equal 2, authors.size
+ assert_equal 3, authors.size
assert_equal 5, authors[0].posts.size
- assert_equal 1, authors[1].posts.size
+ assert_equal 3, authors[1].posts.size
assert_equal 10, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
assert_equal 1, authors[0].categorizations.size
assert_equal 2, authors[1].categorizations.size
@@ -80,15 +80,15 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
def test_eager_association_loading_with_cascaded_two_levels_with_two_has_many_associations
authors = Author.find(:all, :include=>{:posts=>[:comments, :categorizations]}, :order=>"authors.id")
- assert_equal 2, authors.size
+ assert_equal 3, authors.size
assert_equal 5, authors[0].posts.size
- assert_equal 1, authors[1].posts.size
+ assert_equal 3, authors[1].posts.size
assert_equal 10, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
end
def test_eager_association_loading_with_cascaded_two_levels_and_self_table_reference
authors = Author.find(:all, :include=>{:posts=>[:comments, :author]}, :order=>"authors.id")
- assert_equal 2, authors.size
+ assert_equal 3, authors.size
assert_equal 5, authors[0].posts.size
assert_equal authors(:david).name, authors[0].name
assert_equal [authors(:david).name], authors[0].posts.collect{|post| post.author.name}.uniq
@@ -156,9 +156,9 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
def test_eager_association_loading_where_first_level_returns_nil
authors = Author.find(:all, :include => {:post_about_thinking => :comments}, :order => 'authors.id DESC')
- assert_equal [authors(:mary), authors(:david)], authors
+ assert_equal [authors(:bob), authors(:mary), authors(:david)], authors
assert_no_queries do
- authors[1].post_about_thinking.comments.first
+ authors[2].post_about_thinking.comments.first
end
end
end
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 2d8e02e398..6b910ae2a0 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -53,8 +53,8 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_with_ordering
list = Post.find(:all, :include => :comments, :order => "posts.id DESC")
- [:eager_other, :sti_habtm, :sti_post_and_comments, :sti_comments,
- :authorless, :thinking, :welcome
+ [:other_by_mary, :other_by_bob, :misc_by_mary, :misc_by_bob, :eager_other,
+ :sti_habtm, :sti_post_and_comments, :sti_comments, :authorless, :thinking, :welcome
].each_with_index do |post, index|
assert_equal posts(post), list[index]
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 7e070e1746..c6777d0cb3 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
@@ -713,12 +713,12 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
def test_find_grouped
all_posts_from_category1 = Post.find(:all, :conditions => "category_id = 1", :joins => :categories)
grouped_posts_of_category1 = Post.find(:all, :conditions => "category_id = 1", :group => "author_id", :select => 'count(posts.id) as posts_count', :joins => :categories)
- assert_equal 4, all_posts_from_category1.size
- assert_equal 1, grouped_posts_of_category1.size
+ assert_equal 5, all_posts_from_category1.size
+ assert_equal 2, grouped_posts_of_category1.size
end
def test_find_scoped_grouped
- assert_equal 4, categories(:general).posts_grouped_by_title.size
+ assert_equal 5, categories(:general).posts_grouped_by_title.size
assert_equal 1, categories(:technology).posts_grouped_by_title.size
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 4b9f49f1ec..713c492f5e 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -17,11 +17,15 @@ require 'models/developer'
require 'models/subscriber'
require 'models/book'
require 'models/subscription'
+require 'models/essay'
+require 'models/category'
+require 'models/owner'
class HasManyThroughAssociationsTest < ActiveRecord::TestCase
fixtures :posts, :readers, :people, :comments, :authors,
:owners, :pets, :toys, :jobs, :references, :companies,
- :subscribers, :books, :subscriptions, :developers
+ :subscribers, :books, :subscriptions, :developers,
+ :essays, :categories, :owners
# Dummies to force column loads so query counts are clean.
def setup
@@ -449,4 +453,23 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
comment = post.comments.build
assert author.comments.include?(comment)
end
+
+ def test_has_many_through_polymorphic_with_primary_key_option
+ assert_equal [categories(:general)], authors(:david).essay_categories
+
+ authors = Author.joins(:essay_categories).where('categories.id' => categories(:general).id)
+ assert_equal authors(:david), authors.first
+
+ assert_equal [owners(:blackbeard)], authors(:david).essay_owners
+
+ authors = Author.joins(:essay_owners).where("owners.name = 'blackbeard'")
+ assert_equal authors(:david), authors.first
+ end
+
+ def test_has_many_through_with_primary_key_option
+ assert_equal [categories(:general)], authors(:david).essay_categories_2
+
+ authors = Author.joins(:essay_categories_2).where('categories.id' => categories(:general).id)
+ assert_equal authors(:david), authors.first
+ end
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 5d153147f5..39e14b4bfd 100644
--- a/activerecord/test/cases/associations/has_one_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_through_associations_test.rb
@@ -9,9 +9,14 @@ require 'models/member_detail'
require 'models/minivan'
require 'models/dashboard'
require 'models/speedometer'
+require 'models/category'
+require 'models/author'
+require 'models/essay'
+require 'models/owner'
class HasOneThroughAssociationsTest < ActiveRecord::TestCase
- fixtures :member_types, :members, :clubs, :memberships, :sponsors, :organizations, :minivans, :dashboards, :speedometers
+ fixtures :member_types, :members, :clubs, :memberships, :sponsors, :organizations, :minivans,
+ :dashboards, :speedometers, :categories, :authors, :essays, :owners
def setup
@member = members(:groucho)
@@ -212,4 +217,23 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
minivan.dashboard
end
end
+
+ def test_has_one_through_polymorphic_with_primary_key_option
+ assert_equal categories(:general), authors(:david).essay_category
+
+ authors = Author.joins(:essay_category).where('categories.id' => categories(:general).id)
+ assert_equal authors(:david), authors.first
+
+ assert_equal owners(:blackbeard), authors(:david).essay_owner
+
+ authors = Author.joins(:essay_owner).where("owners.name = 'blackbeard'")
+ assert_equal authors(:david), authors.first
+ end
+
+ def test_has_one_through_with_primary_key_option
+ assert_equal categories(:general), authors(:david).essay_category_2
+
+ authors = Author.joins(:essay_category_2).where('categories.id' => categories(:general).id)
+ assert_equal authors(:david), authors.first
+ end
end
diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb
index 7a22ce4dad..385505b109 100644
--- a/activerecord/test/cases/associations/join_model_test.rb
+++ b/activerecord/test/cases/associations/join_model_test.rb
@@ -304,7 +304,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
def test_has_many_going_through_join_model_with_custom_foreign_key
- assert_equal [], posts(:thinking).authors
+ assert_equal [authors(:bob)], posts(:thinking).authors
assert_equal [authors(:mary)], posts(:authorless).authors
end
@@ -394,14 +394,6 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
end
end
- def test_has_many_through_has_many_through
- assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).tags }
- end
-
- def test_has_many_through_habtm
- assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).post_categories }
- end
-
def test_eager_load_has_many_through_has_many
author = Author.find :first, :conditions => ['name = ?', 'David'], :include => :comments, :order => 'comments.id'
SpecialComment.new; VerySpecialComment.new
diff --git a/activerecord/test/cases/associations/nested_through_associations_test.rb b/activerecord/test/cases/associations/nested_through_associations_test.rb
new file mode 100644
index 0000000000..bfc290e877
--- /dev/null
+++ b/activerecord/test/cases/associations/nested_through_associations_test.rb
@@ -0,0 +1,467 @@
+require "cases/helper"
+require 'models/author'
+require 'models/post'
+require 'models/person'
+require 'models/reference'
+require 'models/job'
+require 'models/reader'
+require 'models/comment'
+require 'models/tag'
+require 'models/tagging'
+require 'models/subscriber'
+require 'models/book'
+require 'models/subscription'
+require 'models/rating'
+require 'models/member'
+require 'models/member_detail'
+require 'models/member_type'
+require 'models/sponsor'
+require 'models/club'
+require 'models/organization'
+require 'models/category'
+require 'models/categorization'
+require 'models/membership'
+require 'models/essay'
+
+class NestedThroughAssociationsTest < ActiveRecord::TestCase
+ fixtures :authors, :books, :posts, :subscriptions, :subscribers, :tags, :taggings,
+ :people, :readers, :references, :jobs, :ratings, :comments, :members, :member_details,
+ :member_types, :sponsors, :clubs, :organizations, :categories, :categories_posts,
+ :categorizations, :memberships, :essays
+
+ # Through associations can either use the has_many or has_one macros.
+ #
+ # has_many
+ # - Source reflection can be has_many, has_one, belongs_to or has_and_belongs_to_many
+ # - Through reflection can be has_many, has_one, belongs_to or has_and_belongs_to_many
+ #
+ # has_one
+ # - Source reflection can be has_one or belongs_to
+ # - Through reflection can be has_one or belongs_to
+ #
+ # Additionally, the source reflection and/or through reflection may be subject to
+ # polymorphism and/or STI.
+ #
+ # When testing these, we need to make sure it works via loading the association directly, or
+ # joining the association, or including the association. We also need to ensure that associations
+ # are readonly where relevant.
+
+ # has_many through
+ # Source: has_many through
+ # 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
+
+ assert_includes_and_joins_equal(
+ Author.where('tags.id' => tags(:general).id),
+ [authors(:david)], :tags
+ )
+
+ # 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
+ # Source: has_many
+ # Through: has_many through
+ def test_has_many_through_has_many_through_with_has_many_source_reflection
+ luke, david = subscribers(:first), subscribers(:second)
+
+ author = authors(:david)
+ assert_equal [luke, david, david], author.subscribers.order('subscribers.nick')
+
+ # 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
+ )
+
+ members = assert_queries(4) { Member.includes(:nested_member_types).to_a }
+ assert_no_queries do
+ assert_equal [founding], members.first.nested_member_types
+ end
+ 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
+ )
+
+ members = assert_queries(4) { Member.includes(:nested_sponsors).to_a }
+ assert_no_queries do
+ assert_equal [mustache], members.first.nested_sponsors
+ end
+ end
+
+ # has_many through
+ # Source: has_many through
+ # Through: has_one
+ def test_has_many_through_has_one_with_has_many_through_source_reflection
+ groucho_details, other_details = member_details(:groucho), member_details(:some_other_guy)
+
+ assert_equal [groucho_details, other_details],
+ members(:groucho).organization_member_details.order('member_details.id')
+
+ 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
+ )
+
+ 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
+ # Source: has_many
+ # Through: has_one through
+ def test_has_many_through_has_one_through_with_has_many_source_reflection
+ groucho_details, other_details = member_details(:groucho), member_details(:some_other_guy)
+
+ assert_equal [groucho_details, other_details],
+ members(:groucho).organization_member_details_2.order('member_details.id')
+
+ assert_includes_and_joins_equal(
+ Member.where('member_details.id' => groucho_details.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
+ # Source: has_and_belongs_to_many
+ # Through: has_many
+ def test_has_many_through_has_many_with_has_and_belongs_to_many_source_reflection
+ general, cooking = categories(:general), categories(:cooking)
+
+ assert_equal [general, cooking], authors(:bob).post_categories.order('categories.id')
+
+ assert_includes_and_joins_equal(
+ Author.where('categories.id' => cooking.id),
+ [authors(:bob)], :post_categories
+ )
+
+ authors = assert_queries(3) { Author.includes(:post_categories).to_a.sort_by(&:id) }
+ assert_no_queries do
+ assert_equal [general, cooking], authors[2].post_categories.sort_by(&:id)
+ end
+ end
+
+ # has_many through
+ # Source: has_many
+ # Through: has_and_belongs_to_many
+ def test_has_many_through_has_and_belongs_to_many_with_has_many_source_reflection
+ greetings, more = comments(:greetings), comments(:more_greetings)
+
+ assert_equal [greetings, more], categories(:technology).post_comments.order('comments.id')
+
+ assert_includes_and_joins_equal(
+ Category.where('comments.id' => more.id).order('comments.id'),
+ [categories(:general), categories(:technology)], :post_comments
+ )
+
+ categories = assert_queries(3) { Category.includes(:post_comments).to_a.sort_by(&:id) }
+ assert_no_queries do
+ assert_equal [greetings, more], categories[1].post_comments.sort_by(&:id)
+ end
+ end
+
+ # has_many through
+ # Source: has_many through a habtm
+ # Through: has_many through
+ def test_has_many_through_has_many_with_has_many_through_habtm_source_reflection
+ greetings, more = comments(:greetings), comments(:more_greetings)
+
+ assert_equal [greetings, more], authors(:bob).category_post_comments.order('comments.id')
+
+ assert_includes_and_joins_equal(
+ Author.where('comments.id' => comments(:does_it_hurt).id).order('comments.id'),
+ [authors(:david), authors(:mary)], :category_post_comments
+ )
+
+ authors = assert_queries(5) { Author.includes(:category_post_comments).to_a.sort_by(&:id) }
+ assert_no_queries do
+ assert_equal [greetings, more], authors[2].category_post_comments.sort_by(&:id)
+ end
+ end
+
+ # has_many through
+ # Source: belongs_to
+ # Through: has_many through
+ def test_has_many_through_has_many_through_with_belongs_to_source_reflection
+ general = tags(:general)
+
+ assert_equal [general, general], authors(:david).tagging_tags
+
+ 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
+ # Source: has_many through
+ # Through: belongs_to
+ def test_has_many_through_belongs_to_with_has_many_through_source_reflection
+ welcome_general, thinking_general = taggings(:welcome_general), taggings(:thinking_general)
+
+ assert_equal [welcome_general, thinking_general],
+ categorizations(:david_welcome_general).post_taggings.order('taggings.id')
+
+ assert_includes_and_joins_equal(
+ Categorization.where('taggings.id' => welcome_general.id).order('taggings.id'),
+ [categorizations(:david_welcome_general)], :post_taggings
+ )
+
+ categorizations = assert_queries(4) { Categorization.includes(:post_taggings).to_a.sort_by(&:id) }
+ assert_no_queries do
+ assert_equal [welcome_general, thinking_general], categorizations.first.post_taggings.sort_by(&:id)
+ end
+ end
+
+ # has_one through
+ # Source: has_one through
+ # Through: has_one
+ def test_has_one_through_has_one_with_has_one_through_source_reflection
+ founding = member_types(:founding)
+
+ assert_equal founding, members(:groucho).nested_member_type
+
+ assert_includes_and_joins_equal(
+ Member.where('member_types.id' => 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
+ general = categories(:general)
+
+ assert_equal general, members(:groucho).club_category
+
+ 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
+ author = authors(:david)
+ assert_equal [tags(:general)], author.distinct_tags
+ end
+
+ def test_distinct_has_many_through_a_has_many_through_association_on_through_reflection
+ author = authors(:david)
+ assert_equal [subscribers(:first), subscribers(:second)],
+ author.distinct_subscribers.order('subscribers.nick')
+ end
+
+ def test_nested_has_many_through_with_a_table_referenced_multiple_times
+ author = authors(:bob)
+ assert_equal [posts(:misc_by_bob), posts(:misc_by_mary), posts(:other_by_bob), posts(:other_by_mary)],
+ author.similar_posts.sort_by(&:id)
+
+ # Mary and Bob both have posts in misc, but they are the only ones.
+ authors = Author.joins(:similar_posts).where('posts.id' => posts(:misc_by_bob).id)
+ assert_equal [authors(:mary), authors(:bob)], authors.uniq.sort_by(&:id)
+
+ # Check the polymorphism of taggings is being observed correctly (in both joins)
+ authors = Author.joins(:similar_posts).where('taggings.taggable_type' => 'FakeModel')
+ assert authors.empty?
+ authors = Author.joins(:similar_posts).where('taggings_authors_join.taggable_type' => 'FakeModel')
+ assert authors.empty?
+ end
+
+ def test_has_many_through_with_foreign_key_option_on_through_reflection
+ assert_equal [posts(:welcome), posts(:authorless)], people(:david).agents_posts.order('posts.id')
+ assert_equal [authors(:david)], references(:david_unicyclist).agents_posts_authors
+
+ references = Reference.joins(:agents_posts_authors).where('authors.id' => authors(:david).id)
+ assert_equal [references(:david_unicyclist)], references
+ end
+
+ def test_has_many_through_with_foreign_key_option_on_source_reflection
+ assert_equal [people(:michael), people(:susan)], jobs(:unicyclist).agents.order('people.id')
+
+ jobs = Job.joins(:agents)
+ assert_equal [jobs(:unicyclist), jobs(:unicyclist)], jobs
+ end
+
+ def test_has_many_through_with_sti_on_through_reflection
+ ratings = posts(:sti_comments).special_comments_ratings.sort_by(&:id)
+ assert_equal [ratings(:special_comment_rating), ratings(:sub_special_comment_rating)], ratings
+
+ # Ensure STI is respected in the join
+ scope = Post.joins(:special_comments_ratings).where(:id => posts(:sti_comments).id)
+ assert scope.where("comments.type" => "Comment").empty?
+ assert !scope.where("comments.type" => "SpecialComment").empty?
+ assert !scope.where("comments.type" => "SubSpecialComment").empty?
+ end
+
+ def test_nested_has_many_through_writers_should_raise_error
+ david = authors(:david)
+ subscriber = subscribers(:first)
+
+ assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
+ david.subscribers = [subscriber]
+ end
+
+ assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
+ david.subscriber_ids = [subscriber.id]
+ end
+
+ assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
+ david.subscribers << subscriber
+ end
+
+ assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
+ david.subscribers.delete(subscriber)
+ end
+
+ assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
+ david.subscribers.clear
+ end
+
+ assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
+ david.subscribers.build
+ end
+
+ assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
+ david.subscribers.create
+ end
+ end
+
+ def test_nested_has_one_through_writers_should_raise_error
+ groucho = members(:groucho)
+ founding = member_types(:founding)
+
+ assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
+ groucho.nested_member_type = founding
+ end
+ 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 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) }
+ 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
+
+ # 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 = assert_queries(4) { Author.includes(:misc_post_first_blue_tags_2).to_a.sort_by(&:id) }
+ assert_no_queries do
+ assert_equal [blue], authors[2].misc_post_first_blue_tags_2
+ end
+ 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
+
+ organizations = Organization.joins(:author_essay_categories).
+ where('categories.id' => categories(:general).id)
+ assert_equal [organizations(:nsa)], organizations
+
+ assert_equal categories(:general), organizations(:nsa).author_owned_essay_category
+
+ organizations = Organization.joins(:author_owned_essay_category).
+ where('categories.id' => categories(:general).id)
+ assert_equal [organizations(:nsa)], organizations
+ end
+
+ private
+
+ def assert_includes_and_joins_equal(query, expected, association)
+ actual = assert_queries(1) { query.joins(association).to_a.uniq }
+ assert_equal expected, actual
+
+ actual = assert_queries(1) { query.includes(association).to_a.uniq }
+ assert_equal expected, actual
+ end
+end
diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb
index dcc49e12ca..9e72ac4250 100644
--- a/activerecord/test/cases/batches_test.rb
+++ b/activerecord/test/cases/batches_test.rb
@@ -24,7 +24,7 @@ class EachTest < ActiveRecord::TestCase
end
def test_each_should_execute_if_id_is_in_select
- assert_queries(4) do
+ assert_queries(6) do
Post.find_each(:select => "id, title, type", :batch_size => 2) do |post|
assert_kind_of Post, post
end
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index c058196078..4c9475f1cd 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -123,11 +123,13 @@ class FinderTest < ActiveRecord::TestCase
def test_find_all_with_limit_and_offset_and_multiple_order_clauses
first_three_posts = Post.find :all, :order => 'author_id, id', :limit => 3, :offset => 0
second_three_posts = Post.find :all, :order => ' author_id,id ', :limit => 3, :offset => 3
- last_posts = Post.find :all, :order => ' author_id, id ', :limit => 3, :offset => 6
+ third_three_posts = Post.find :all, :order => ' author_id, id ', :limit => 3, :offset => 6
+ last_posts = Post.find :all, :order => ' author_id, id ', :limit => 3, :offset => 9
assert_equal [[0,3],[1,1],[1,2]], first_three_posts.map { |p| [p.author_id, p.id] }
assert_equal [[1,4],[1,5],[1,6]], second_three_posts.map { |p| [p.author_id, p.id] }
- assert_equal [[2,7]], last_posts.map { |p| [p.author_id, p.id] }
+ assert_equal [[2,7],[2,9],[2,11]], third_three_posts.map { |p| [p.author_id, p.id] }
+ assert_equal [[3,8],[3,10]], last_posts.map { |p| [p.author_id, p.id] }
end
diff --git a/activerecord/test/cases/json_serialization_test.rb b/activerecord/test/cases/json_serialization_test.rb
index 5da7f9e1b9..8664d63e8f 100644
--- a/activerecord/test/cases/json_serialization_test.rb
+++ b/activerecord/test/cases/json_serialization_test.rb
@@ -181,7 +181,11 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase
def test_should_allow_except_option_for_list_of_authors
ActiveRecord::Base.include_root_in_json = false
authors = [@david, @mary]
- assert_equal %([{"id":1},{"id":2}]), ActiveSupport::JSON.encode(authors, :except => [:name, :author_address_id, :author_address_extra_id])
+ encoded = ActiveSupport::JSON.encode(authors, :except => [
+ :name, :author_address_id, :author_address_extra_id,
+ :organization_id, :owned_essay_id
+ ])
+ assert_equal %([{"id":1},{"id":2}]), encoded
ensure
ActiveRecord::Base.include_root_in_json = true
end
@@ -196,7 +200,7 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase
)
['"name":"David"', '"posts":[', '{"id":1}', '{"id":2}', '{"id":4}',
- '{"id":5}', '{"id":6}', '"name":"Mary"', '"posts":[{"id":7}]'].each do |fragment|
+ '{"id":5}', '{"id":6}', '"name":"Mary"', '"posts":[', '{"id":7}', '{"id":9}'].each do |fragment|
assert json.include?(fragment), json
end
end
diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb
index eeb619ac2f..a85ba623e1 100644
--- a/activerecord/test/cases/reflection_test.rb
+++ b/activerecord/test/cases/reflection_test.rb
@@ -7,6 +7,16 @@ require 'models/subscriber'
require 'models/ship'
require 'models/pirate'
require 'models/price_estimate'
+require 'models/essay'
+require 'models/author'
+require 'models/organization'
+require 'models/post'
+require 'models/tagging'
+require 'models/category'
+require 'models/book'
+require 'models/subscriber'
+require 'models/subscription'
+require 'models/tag'
class ReflectionTest < ActiveRecord::TestCase
include ActiveRecord::Reflection
@@ -190,6 +200,60 @@ class ReflectionTest < ActiveRecord::TestCase
def test_has_many_through_reflection
assert_kind_of ThroughReflection, Subscriber.reflect_on_association(:books)
end
+
+ def test_through_reflection_chain
+ expected = [
+ Author.reflect_on_association(:essay_categories),
+ Author.reflect_on_association(:essays),
+ Organization.reflect_on_association(:authors)
+ ]
+ actual = Organization.reflect_on_association(:author_essay_categories).through_reflection_chain
+
+ assert_equal expected, actual
+ end
+
+ def test_through_conditions
+ expected = [
+ ["tags.name = 'Blue'"],
+ ["taggings.comment = 'first'"],
+ ["posts.title LIKE 'misc post%'"]
+ ]
+ actual = Author.reflect_on_association(:misc_post_first_blue_tags).through_conditions
+ assert_equal expected, actual
+
+ expected = [
+ ["tags.name = 'Blue'", "taggings.comment = 'first'", "posts.title LIKE 'misc post%'"],
+ [],
+ []
+ ]
+ actual = Author.reflect_on_association(:misc_post_first_blue_tags_2).through_conditions
+ assert_equal expected, actual
+ end
+
+ def test_nested?
+ assert !Author.reflect_on_association(:comments).nested?
+ assert Author.reflect_on_association(:tags).nested?
+
+ # Only goes :through once, but the through_reflection is a has_and_belongs_to_many, so this is
+ # a nested through association
+ assert Category.reflect_on_association(:post_comments).nested?
+ end
+
+ def test_association_primary_key
+ # Normal association
+ assert_equal "id", Author.reflect_on_association(:posts).association_primary_key.to_s
+ assert_equal "name", Author.reflect_on_association(:essay).association_primary_key.to_s
+
+ # Through association (uses the :primary_key option from the source reflection)
+ assert_equal "nick", Author.reflect_on_association(:subscribers).association_primary_key.to_s
+ assert_equal "name", Author.reflect_on_association(:essay_category).association_primary_key.to_s
+ assert_equal "custom_primary_key", Author.reflect_on_association(:tags_with_primary_key).association_primary_key.to_s # nested
+ end
+
+ def test_active_record_primary_key
+ assert_equal "nick", Subscriber.reflect_on_association(:subscriptions).active_record_primary_key.to_s
+ assert_equal "name", Author.reflect_on_association(:essay).active_record_primary_key.to_s
+ end
def test_collection_association
assert Pirate.reflect_on_association(:birds).collection?
diff --git a/activerecord/test/cases/relation_scoping_test.rb b/activerecord/test/cases/relation_scoping_test.rb
index a27e2e72cd..bf41199b77 100644
--- a/activerecord/test/cases/relation_scoping_test.rb
+++ b/activerecord/test/cases/relation_scoping_test.rb
@@ -336,7 +336,7 @@ class DefaultScopingTest < ActiveRecord::TestCase
end
records = klass.all
- assert_equal 1, records.length
+ assert_equal 3, records.length
assert_equal 2, records.first.author_id
end
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index f4f3dc4d5a..268cea27be 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -253,27 +253,27 @@ class RelationTest < ActiveRecord::TestCase
def test_find_with_preloaded_associations
assert_queries(2) do
- posts = Post.preload(:comments)
+ posts = Post.preload(:comments).order('posts.id')
assert posts.first.comments.first
end
assert_queries(2) do
- posts = Post.preload(:comments).to_a
+ posts = Post.preload(:comments).order('posts.id').to_a
assert posts.first.comments.first
end
assert_queries(2) do
- posts = Post.preload(:author)
+ posts = Post.preload(:author).order('posts.id')
assert posts.first.author
end
assert_queries(2) do
- posts = Post.preload(:author).to_a
+ posts = Post.preload(:author).order('posts.id').to_a
assert posts.first.author
end
assert_queries(3) do
- posts = Post.preload(:author, :comments).to_a
+ posts = Post.preload(:author, :comments).order('posts.id').to_a
assert posts.first.author
assert posts.first.comments.first
end
@@ -281,22 +281,22 @@ class RelationTest < ActiveRecord::TestCase
def test_find_with_included_associations
assert_queries(2) do
- posts = Post.includes(:comments)
+ posts = Post.includes(:comments).order('posts.id')
assert posts.first.comments.first
end
assert_queries(2) do
- posts = Post.scoped.includes(:comments)
+ posts = Post.scoped.includes(:comments).order('posts.id')
assert posts.first.comments.first
end
assert_queries(2) do
- posts = Post.includes(:author)
+ posts = Post.includes(:author).order('posts.id')
assert posts.first.author
end
assert_queries(3) do
- posts = Post.includes(:author, :comments).to_a
+ posts = Post.includes(:author, :comments).order('posts.id').to_a
assert posts.first.author
assert posts.first.comments.first
end
@@ -430,7 +430,7 @@ class RelationTest < ActiveRecord::TestCase
def test_last
authors = Author.scoped
- assert_equal authors(:mary), authors.last
+ assert_equal authors(:bob), authors.last
end
def test_destroy_all
@@ -508,22 +508,22 @@ class RelationTest < ActiveRecord::TestCase
def test_count
posts = Post.scoped
- assert_equal 7, posts.count
- assert_equal 7, posts.count(:all)
- assert_equal 7, posts.count(:id)
+ assert_equal 11, posts.count
+ assert_equal 11, posts.count(:all)
+ assert_equal 11, posts.count(:id)
assert_equal 1, posts.where('comments_count > 1').count
- assert_equal 5, posts.where(:comments_count => 0).count
+ assert_equal 9, posts.where(:comments_count => 0).count
end
def test_count_with_distinct
posts = Post.scoped
assert_equal 3, posts.count(:comments_count, :distinct => true)
- assert_equal 7, posts.count(:comments_count, :distinct => false)
+ assert_equal 11, posts.count(:comments_count, :distinct => false)
assert_equal 3, posts.select(:comments_count).count(:distinct => true)
- assert_equal 7, posts.select(:comments_count).count(:distinct => false)
+ assert_equal 11, posts.select(:comments_count).count(:distinct => false)
end
def test_count_explicit_columns
@@ -533,7 +533,7 @@ class RelationTest < ActiveRecord::TestCase
assert_equal [0], posts.select('comments_count').where('id is not null').group('id').order('id').count.values.uniq
assert_equal 0, posts.where('id is not null').select('comments_count').count
- assert_equal 7, posts.select('comments_count').count('id')
+ assert_equal 11, posts.select('comments_count').count('id')
assert_equal 0, posts.select('comments_count').count
assert_equal 0, posts.count(:comments_count)
assert_equal 0, posts.count('comments_count')
@@ -548,12 +548,12 @@ class RelationTest < ActiveRecord::TestCase
def test_size
posts = Post.scoped
- assert_queries(1) { assert_equal 7, posts.size }
+ assert_queries(1) { assert_equal 11, posts.size }
assert ! posts.loaded?
best_posts = posts.where(:comments_count => 0)
best_posts.to_a # force load
- assert_no_queries { assert_equal 5, best_posts.size }
+ assert_no_queries { assert_equal 9, best_posts.size }
end
def test_count_complex_chained_relations