From b689834bcf2730353d066277f43047f10abb8d30 Mon Sep 17 00:00:00 2001 From: Bodaniel Jeanes Date: Sun, 26 Sep 2010 22:17:18 +1000 Subject: Initial nested_has_many_through support [#1152] --- .../test/cases/associations/join_model_test.rb | 8 ---- .../nested_has_many_through_associations_test.rb | 43 ++++++++++++++++++++++ activerecord/test/fixtures/books.yml | 2 + activerecord/test/models/author.rb | 14 +++++-- activerecord/test/models/book.rb | 2 + activerecord/test/schema/schema.rb | 1 + 6 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 activerecord/test/cases/associations/nested_has_many_through_associations_test.rb (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index f131dc01f6..0b1a3db1e4 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -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_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb new file mode 100644 index 0000000000..36de709ffc --- /dev/null +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -0,0 +1,43 @@ +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/owner' +require 'models/pet' +require 'models/toy' +require 'models/contract' +require 'models/company' +require 'models/developer' +require 'models/subscriber' +require 'models/book' +require 'models/subscription' + +class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase + fixtures :authors, :books, :posts, :subscriptions, :subscribers, :tags, :taggings + + def test_has_many_through_a_has_many_through_association_on_source_reflection + author = authors(:david) + assert_equal [tags(:general), tags(:general)], author.tags + end + + def test_has_many_through_a_has_many_through_association_on_through_reflection + author = authors(:david) + assert_equal [subscribers(:first), subscribers(:second), subscribers(:second)], author.subscribers + 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 + end +end \ No newline at end of file diff --git a/activerecord/test/fixtures/books.yml b/activerecord/test/fixtures/books.yml index 473663ff5b..fb48645456 100644 --- a/activerecord/test/fixtures/books.yml +++ b/activerecord/test/fixtures/books.yml @@ -1,7 +1,9 @@ awdr: + author_id: 1 id: 1 name: "Agile Web Development with Rails" rfr: + author_id: 1 id: 2 name: "Ruby for Rails" diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index 34bfd2d881..94810e2f34 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -83,14 +83,20 @@ class Author < ActiveRecord::Base has_many :author_favorites has_many :favorite_authors, :through => :author_favorites, :order => 'name' - has_many :tagging, :through => :posts # through polymorphic has_one - has_many :taggings, :through => :posts, :source => :taggings # through polymorphic has_many - has_many :tags, :through => :posts # through has_many :through + has_many :tagging, :through => :posts # through polymorphic has_one + has_many :taggings, :through => :posts, :source => :taggings # through polymorphic has_many + has_many :tags, :through => :posts # through has_many :through (on source reflection + polymorphic) + has_many :distinct_tags, :through => :posts, :source => :tags, :select => "DISTINCT tags.*", :order => "tags.name" has_many :post_categories, :through => :posts, :source => :categories + has_many :books + has_many :subscriptions, :through => :books + has_many :subscribers, :through => :subscriptions # through has_many :through (on through reflection) + has_many :distinct_subscribers, :through => :subscriptions, :source => :subscriber, :select => "DISTINCT subscribers.*", :order => "subscribers.nick" + has_one :essay, :primary_key => :name, :as => :writer - belongs_to :author_address, :dependent => :destroy + belongs_to :author_address, :dependent => :destroy belongs_to :author_address_extra, :dependent => :delete, :class_name => "AuthorAddress" scope :relation_include_posts, includes(:posts) diff --git a/activerecord/test/models/book.rb b/activerecord/test/models/book.rb index 1e030b4f59..d27d0af77c 100644 --- a/activerecord/test/models/book.rb +++ b/activerecord/test/models/book.rb @@ -1,4 +1,6 @@ class Book < ActiveRecord::Base + has_many :authors + has_many :citations, :foreign_key => 'book1_id' has_many :references, :through => :citations, :source => :reference_of, :uniq => true diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index ea62833d81..dbd5da45eb 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -71,6 +71,7 @@ ActiveRecord::Schema.define do end create_table :books, :force => true do |t| + t.integer :author_id t.column :name, :string end -- cgit v1.2.3 From 14c4881f9c7bf4eae61e548542ee309c013e1fca Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Thu, 30 Sep 2010 22:01:03 +0100 Subject: Prevent test_has_many_through_a_has_many_through_association_on_through_reflection failing for me due to ordering of the results --- activerecord/test/models/author.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index 94810e2f34..1efb4fc095 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -84,14 +84,14 @@ class Author < ActiveRecord::Base has_many :favorite_authors, :through => :author_favorites, :order => 'name' has_many :tagging, :through => :posts # through polymorphic has_one - has_many :taggings, :through => :posts, :source => :taggings # through polymorphic has_many + has_many :taggings, :through => :posts, :source => :taggings # through polymorphic has_many TODO: Why is the :source needed? has_many :tags, :through => :posts # through has_many :through (on source reflection + polymorphic) has_many :distinct_tags, :through => :posts, :source => :tags, :select => "DISTINCT tags.*", :order => "tags.name" has_many :post_categories, :through => :posts, :source => :categories has_many :books has_many :subscriptions, :through => :books - has_many :subscribers, :through => :subscriptions # through has_many :through (on through reflection) + has_many :subscribers, :through => :subscriptions, :order => "subscribers.nick" # through has_many :through (on through reflection) has_many :distinct_subscribers, :through => :subscriptions, :source => :subscriber, :select => "DISTINCT subscribers.*", :order => "subscribers.nick" has_one :essay, :primary_key => :name, :as => :writer -- cgit v1.2.3 From 4f69a61107d9d59f96bf249ef077483e90babe72 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Fri, 1 Oct 2010 13:10:41 +0100 Subject: Started implementing nested :through associations by using the existing structure of ThroughAssociationScope rather than layering a module over the top --- .../nested_has_many_through_associations_test.rb | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 36de709ffc..539e6e000a 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -21,23 +21,23 @@ require 'models/subscription' class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase fixtures :authors, :books, :posts, :subscriptions, :subscribers, :tags, :taggings - def test_has_many_through_a_has_many_through_association_on_source_reflection - author = authors(:david) - assert_equal [tags(:general), tags(:general)], author.tags - end +# def test_has_many_through_a_has_many_through_association_on_source_reflection +# author = authors(:david) +# assert_equal [tags(:general), tags(:general)], author.tags +# end def test_has_many_through_a_has_many_through_association_on_through_reflection author = authors(:david) assert_equal [subscribers(:first), subscribers(:second), subscribers(:second)], author.subscribers 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_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 - end -end \ No newline at end of file +# 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 +# end +end -- cgit v1.2.3 From 34ee586e993ad9e466b81f376fa92feb5d312b4c Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sat, 2 Oct 2010 18:50:17 +0100 Subject: Integrate nested support into ThroughAssociationScope, using my concept of generating a 'chain' of reflections to be joined. It seems to work at the moment, all existing tests are passing. There may be further complications as we add more test cases for nested associations, though. --- .../nested_has_many_through_associations_test.rb | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 539e6e000a..938643b1b3 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -21,23 +21,23 @@ require 'models/subscription' class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase fixtures :authors, :books, :posts, :subscriptions, :subscribers, :tags, :taggings -# def test_has_many_through_a_has_many_through_association_on_source_reflection -# author = authors(:david) -# assert_equal [tags(:general), tags(:general)], author.tags -# end + def test_has_many_through_a_has_many_through_association_on_source_reflection + author = authors(:david) + assert_equal [tags(:general), tags(:general)], author.tags + end def test_has_many_through_a_has_many_through_association_on_through_reflection author = authors(:david) assert_equal [subscribers(:first), subscribers(:second), subscribers(:second)], author.subscribers 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_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 -# 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 + end end -- cgit v1.2.3 From a34391c3b495bad268204bdf4f6b3483a61abcd5 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sat, 2 Oct 2010 21:45:46 +0100 Subject: Add support for table aliasing, with a test that needs aliasing in order to work correctly. This test incidentally provides a more complicated test case (4 inner joins, 2 using polymorphism). --- .../nested_has_many_through_associations_test.rb | 5 +++++ activerecord/test/fixtures/authors.yml | 4 ++++ activerecord/test/fixtures/posts.yml | 14 ++++++++++++++ activerecord/test/fixtures/taggings.yml | 12 ++++++++++++ activerecord/test/fixtures/tags.yml | 2 +- activerecord/test/models/author.rb | 3 ++- 6 files changed, 38 insertions(+), 2 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 938643b1b3..925a9598fb 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -40,4 +40,9 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase author = authors(:david) assert_equal [subscribers(:first), subscribers(:second)], author.distinct_subscribers 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)], author.similar_posts.sort_by(&:id) + end end diff --git a/activerecord/test/fixtures/authors.yml b/activerecord/test/fixtures/authors.yml index de2ec7d38b..6f13ec4dac 100644 --- a/activerecord/test/fixtures/authors.yml +++ b/activerecord/test/fixtures/authors.yml @@ -7,3 +7,7 @@ david: mary: id: 2 name: Mary + +bob: + id: 3 + name: Bob diff --git a/activerecord/test/fixtures/posts.yml b/activerecord/test/fixtures/posts.yml index f817493190..ca6d4c2fe1 100644 --- a/activerecord/test/fixtures/posts.yml +++ b/activerecord/test/fixtures/posts.yml @@ -50,3 +50,17 @@ eager_other: title: eager loading with OR'd conditions body: hello type: Post + +misc_by_bob: + id: 8 + author_id: 3 + title: misc post by bob + body: hello + type: Post + +misc_by_mary: + id: 9 + author_id: 2 + title: misc post by mary + body: hello + type: Post diff --git a/activerecord/test/fixtures/taggings.yml b/activerecord/test/fixtures/taggings.yml index 3db6a4c079..7cc7198ded 100644 --- a/activerecord/test/fixtures/taggings.yml +++ b/activerecord/test/fixtures/taggings.yml @@ -26,3 +26,15 @@ godfather: orphaned: id: 5 tag_id: 1 + +misc_post_by_bob: + id: 6 + tag_id: 2 + taggable_id: 8 + taggable_type: Post + +misc_post_by_mary: + id: 7 + tag_id: 2 + taggable_id: 9 + taggable_type: Post diff --git a/activerecord/test/fixtures/tags.yml b/activerecord/test/fixtures/tags.yml index 7610fd38b9..6cb886dc46 100644 --- a/activerecord/test/fixtures/tags.yml +++ b/activerecord/test/fixtures/tags.yml @@ -4,4 +4,4 @@ general: misc: id: 2 - name: Misc \ No newline at end of file + name: Misc diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index 1efb4fc095..1fbd729b60 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -84,8 +84,9 @@ class Author < ActiveRecord::Base has_many :favorite_authors, :through => :author_favorites, :order => 'name' has_many :tagging, :through => :posts # through polymorphic has_one - has_many :taggings, :through => :posts, :source => :taggings # through polymorphic has_many TODO: Why is the :source needed? + has_many :taggings, :through => :posts # through polymorphic has_many has_many :tags, :through => :posts # through has_many :through (on source reflection + polymorphic) + has_many :similar_posts, :through => :tags, :source => :tagged_posts has_many :distinct_tags, :through => :posts, :source => :tags, :select => "DISTINCT tags.*", :order => "tags.name" has_many :post_categories, :through => :posts, :source => :categories -- cgit v1.2.3 From 43711083dd34252877bab9df43d3db0fd42feeb2 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sun, 3 Oct 2010 11:56:32 +0100 Subject: Fix the tests (I have actually verified that these are also the 'right' fixes, rather than just making the tests pass again) --- .../associations/cascaded_eager_loading_test.rb | 18 +++++++++--------- activerecord/test/cases/associations/eager_test.rb | 4 ++-- activerecord/test/cases/batches_test.rb | 2 +- activerecord/test/cases/finder_test.rb | 2 +- activerecord/test/cases/json_serialization_test.rb | 2 +- activerecord/test/cases/relations_test.rb | 20 ++++++++++---------- 6 files changed, 24 insertions(+), 24 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb index b93e49613d..8bb8f3e359 100644 --- a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb +++ b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb @@ -13,17 +13,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 2, authors[1].posts.size assert_equal 9, 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 2, authors[1].posts.size assert_equal 9, 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 @@ -54,15 +54,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 2, authors[1].posts.size assert_equal 9, 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 @@ -130,9 +130,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 40859d425f..1669c4d5f4 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 + [: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/batches_test.rb b/activerecord/test/cases/batches_test.rb index dcc49e12ca..70883ad30f 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(5) 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 26b5096255..e73f58fdc7 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -127,7 +127,7 @@ class FinderTest < ActiveRecord::TestCase 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],[3,8]], 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..430be003ac 100644 --- a/activerecord/test/cases/json_serialization_test.rb +++ b/activerecord/test/cases/json_serialization_test.rb @@ -196,7 +196,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/relations_test.rb b/activerecord/test/cases/relations_test.rb index d642aeed8b..fec5e6731f 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -434,7 +434,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 @@ -507,22 +507,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 9, posts.count + assert_equal 9, posts.count(:all) + assert_equal 9, posts.count(:id) assert_equal 1, posts.where('comments_count > 1').count - assert_equal 5, posts.where(:comments_count => 0).count + assert_equal 7, 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 9, 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 9, posts.select(:comments_count).count(:distinct => false) end def test_count_explicit_columns @@ -532,7 +532,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 9, 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') @@ -547,12 +547,12 @@ class RelationTest < ActiveRecord::TestCase def test_size posts = Post.scoped - assert_queries(1) { assert_equal 7, posts.size } + assert_queries(1) { assert_equal 9, 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 7, best_posts.size } end def test_count_complex_chained_relations -- cgit v1.2.3 From 3cc35633872a0072764d8edb20f1fc4e14adf729 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 5 Oct 2010 20:20:27 +0100 Subject: A failing test for a nested has many through association loaded via Foo.joins(:bar) --- .../cases/associations/nested_has_many_through_associations_test.rb | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 925a9598fb..a5d3f27702 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -45,4 +45,10 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase author = authors(:bob) assert_equal [posts(:misc_by_bob), posts(:misc_by_mary)], author.similar_posts.sort_by(&:id) end + + def test_nested_has_many_through_as_a_join + # All authors with subscribers where one of the subscribers' nick is 'alterself' + authors = Author.joins(:subscribers).where('subscribers.nick' => 'alterself') + assert_equal [authors(:david)], authors + end end -- cgit v1.2.3 From f2b41914d6be935182d37e0c0d491352ac3de043 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Wed, 6 Oct 2010 12:06:51 +0100 Subject: Refactoring JoinDependency and friends. This improves the code (IMO) including adding some explanatory comments, but more importantly structures it in such a way as to allow a JoinAssociation to produce an arbitrary number of actual joins, which will be necessary for nested has many through support. Also added 3 tests covering functionality which existed but was not previously covered. --- .../associations/cascaded_eager_loading_test.rb | 8 ++++---- activerecord/test/cases/associations/eager_test.rb | 8 ++++---- .../associations/inner_join_association_test.rb | 24 +++++++++++++++++++++- .../test/cases/associations/join_model_test.rb | 4 ++-- activerecord/test/cases/finder_test.rb | 2 +- activerecord/test/fixtures/comments.yml | 6 ++++++ activerecord/test/models/comment.rb | 3 +++ 7 files changed, 43 insertions(+), 12 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb index 8bb8f3e359..0e9c8a2639 100644 --- a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb +++ b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb @@ -16,7 +16,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase assert_equal 3, authors.size assert_equal 5, authors[0].posts.size assert_equal 2, authors[1].posts.size - assert_equal 9, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i} + 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 @@ -24,7 +24,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase assert_equal 3, authors.size assert_equal 5, authors[0].posts.size assert_equal 2, authors[1].posts.size - assert_equal 9, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i} + 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 end @@ -35,7 +35,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase end authors = Author.joins(:posts).eager_load(:comments).where(:posts => {:taggings_count => 1}).all assert_equal 1, assert_no_queries { authors.size } - assert_equal 9, assert_no_queries { authors[0].comments.size } + assert_equal 10, assert_no_queries { authors[0].comments.size } end def test_eager_association_loading_grafts_stashed_associations_to_correct_parent @@ -57,7 +57,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase assert_equal 3, authors.size assert_equal 5, authors[0].posts.size assert_equal 2, authors[1].posts.size - assert_equal 9, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i} + 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 diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 1669c4d5f4..2ff0714e9f 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -174,7 +174,7 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_eager_association_loading_with_belongs_to comments = Comment.find(:all, :include => :post) - assert_equal 10, comments.length + assert_equal 11, comments.length titles = comments.map { |c| c.post.title } assert titles.include?(posts(:welcome).title) assert titles.include?(posts(:sti_post_and_comments).title) @@ -532,7 +532,7 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_eager_has_many_with_association_inheritance post = Post.find(4, :include => [ :special_comments ]) post.special_comments.each do |special_comment| - assert_equal "SpecialComment", special_comment.class.to_s + assert special_comment.is_a?(SpecialComment) end end @@ -726,8 +726,8 @@ class EagerAssociationTest < ActiveRecord::TestCase posts = assert_queries(2) do Post.find(:all, :joins => :comments, :include => :author, :order => 'comments.id DESC') end - assert_equal posts(:eager_other), posts[0] - assert_equal authors(:mary), assert_no_queries { posts[0].author} + assert_equal posts(:eager_other), posts[1] + assert_equal authors(:mary), assert_no_queries { posts[1].author} end def test_eager_loading_with_conditions_on_joined_table_preloads diff --git a/activerecord/test/cases/associations/inner_join_association_test.rb b/activerecord/test/cases/associations/inner_join_association_test.rb index 4ba867dc7c..780eabc443 100644 --- a/activerecord/test/cases/associations/inner_join_association_test.rb +++ b/activerecord/test/cases/associations/inner_join_association_test.rb @@ -4,9 +4,12 @@ require 'models/comment' require 'models/author' require 'models/category' require 'models/categorization' +require 'models/tagging' +require 'models/tag' class InnerJoinAssociationTest < ActiveRecord::TestCase - fixtures :authors, :posts, :comments, :categories, :categories_posts, :categorizations + fixtures :authors, :posts, :comments, :categories, :categories_posts, :categorizations, + :taggings, :tags def test_construct_finder_sql_applies_aliases_tables_on_association_conditions result = Author.joins(:thinking_posts, :welcome_posts).to_a @@ -62,4 +65,23 @@ 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? + end end diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index 0b1a3db1e4..4b7a8b494d 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -398,7 +398,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase author = Author.find :first, :conditions => ['name = ?', 'David'], :include => :comments, :order => 'comments.id' SpecialComment.new; VerySpecialComment.new assert_no_queries do - assert_equal [1,2,3,5,6,7,8,9,10], author.comments.collect(&:id) + assert_equal [1,2,3,5,6,7,8,9,10,12], author.comments.collect(&:id) end end @@ -500,7 +500,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_has_many_through_collection_size_doesnt_load_target_if_not_loaded author = authors(:david) - assert_equal 9, author.comments.size + assert_equal 10, author.comments.size assert !author.comments.loaded? end diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index e73f58fdc7..0476fc94df 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -259,7 +259,7 @@ class FinderTest < ActiveRecord::TestCase end def test_find_on_association_proxy_conditions - assert_equal [1, 2, 3, 5, 6, 7, 8, 9, 10], Comment.find_all_by_post_id(authors(:david).posts).map(&:id).sort + assert_equal [1, 2, 3, 5, 6, 7, 8, 9, 10, 12], Comment.find_all_by_post_id(authors(:david).posts).map(&:id).sort end def test_find_on_hash_conditions_with_range diff --git a/activerecord/test/fixtures/comments.yml b/activerecord/test/fixtures/comments.yml index 97d77f8b9a..ddbb823c49 100644 --- a/activerecord/test/fixtures/comments.yml +++ b/activerecord/test/fixtures/comments.yml @@ -57,3 +57,9 @@ eager_other_comment1: post_id: 7 body: go crazy type: SpecialComment + +sub_special_comment: + id: 12 + post_id: 4 + body: Sub special comment + type: SubSpecialComment diff --git a/activerecord/test/models/comment.rb b/activerecord/test/models/comment.rb index 9f6e2d3b71..88061b2145 100644 --- a/activerecord/test/models/comment.rb +++ b/activerecord/test/models/comment.rb @@ -23,6 +23,9 @@ class SpecialComment < Comment end end +class SubSpecialComment < SpecialComment +end + class VerySpecialComment < Comment def self.what_are_you 'a very special comment...' -- cgit v1.2.3 From ab5a9335020eff0da35b62b86a62ed8587a4d598 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sat, 9 Oct 2010 22:00:33 +0100 Subject: Add support for nested through associations in JoinAssociation. Hence Foo.joins(:bar) will work for through associations. There is some duplicated code now, which will be refactored. --- .../nested_has_many_through_associations_test.rb | 59 ++++++++++++++++++++-- activerecord/test/fixtures/ratings.yml | 14 +++++ activerecord/test/models/comment.rb | 1 + activerecord/test/models/job.rb | 2 + activerecord/test/models/person.rb | 3 ++ activerecord/test/models/post.rb | 2 + activerecord/test/models/rating.rb | 3 ++ activerecord/test/models/reference.rb | 2 + activerecord/test/schema/schema.rb | 5 ++ 9 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 activerecord/test/fixtures/ratings.yml create mode 100644 activerecord/test/models/rating.rb (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index a5d3f27702..ba75b70941 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -17,18 +17,37 @@ require 'models/developer' require 'models/subscriber' require 'models/book' require 'models/subscription' +require 'models/rating' + +# NOTE: Some of these tests might not really test "nested" HMT associations, as opposed to ones which +# are just one level deep. But it's all the same thing really, as the "nested" code is being +# written in a generic way which applies to "non-nested" HMT associations too. So let's just shove +# all useful tests in here for now and then work out where they ought to live properly later. class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase - fixtures :authors, :books, :posts, :subscriptions, :subscribers, :tags, :taggings + fixtures :authors, :books, :posts, :subscriptions, :subscribers, :tags, :taggings, + :people, :readers, :references, :jobs, :ratings, :comments def test_has_many_through_a_has_many_through_association_on_source_reflection author = authors(:david) assert_equal [tags(:general), tags(:general)], author.tags + + # Only David has a Post tagged with General + authors = Author.joins(:tags).where('tags.id' => tags(:general).id) + assert_equal [authors(:david)], authors.uniq + + # This ensures that the polymorphism of taggings is being observed correctly + authors = Author.joins(:tags).where('taggings.taggable_type' => 'FakeModel') + assert authors.empty? end def test_has_many_through_a_has_many_through_association_on_through_reflection author = authors(:david) assert_equal [subscribers(:first), subscribers(:second), subscribers(:second)], author.subscribers + + # All authors with subscribers where one of the subscribers' nick is 'alterself' + authors = Author.joins(:subscribers).where('subscribers.nick' => 'alterself') + assert_equal [authors(:david)], authors end def test_distinct_has_many_through_a_has_many_through_association_on_source_reflection @@ -44,11 +63,41 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase 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)], 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_nested_has_many_through_as_a_join - # All authors with subscribers where one of the subscribers' nick is 'alterself' - authors = Author.joins(:subscribers).where('subscribers.nick' => 'alterself') - assert_equal [authors(:david)], authors + def test_has_many_through_with_foreign_key_option_on_through_reflection + assert_equal [posts(:welcome), posts(:authorless)], people(:david).agents_posts + 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 + + 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 end diff --git a/activerecord/test/fixtures/ratings.yml b/activerecord/test/fixtures/ratings.yml new file mode 100644 index 0000000000..34e208efa3 --- /dev/null +++ b/activerecord/test/fixtures/ratings.yml @@ -0,0 +1,14 @@ +normal_comment_rating: + id: 1 + comment_id: 8 + value: 1 + +special_comment_rating: + id: 2 + comment_id: 6 + value: 1 + +sub_special_comment_rating: + id: 3 + comment_id: 12 + value: 1 diff --git a/activerecord/test/models/comment.rb b/activerecord/test/models/comment.rb index 88061b2145..1a3fb42b66 100644 --- a/activerecord/test/models/comment.rb +++ b/activerecord/test/models/comment.rb @@ -7,6 +7,7 @@ class Comment < ActiveRecord::Base :conditions => { "posts.author_id" => 1 } belongs_to :post, :counter_cache => true + has_many :ratings def self.what_are_you 'a comment...' diff --git a/activerecord/test/models/job.rb b/activerecord/test/models/job.rb index 3333a02e27..46b1d87aa1 100644 --- a/activerecord/test/models/job.rb +++ b/activerecord/test/models/job.rb @@ -2,4 +2,6 @@ class Job < ActiveRecord::Base has_many :references has_many :people, :through => :references belongs_to :ideal_reference, :class_name => 'Reference' + + has_many :agents, :through => :people end diff --git a/activerecord/test/models/person.rb b/activerecord/test/models/person.rb index 951ec93c53..d35c51b660 100644 --- a/activerecord/test/models/person.rb +++ b/activerecord/test/models/person.rb @@ -13,6 +13,9 @@ class Person < ActiveRecord::Base belongs_to :primary_contact, :class_name => 'Person' has_many :agents, :class_name => 'Person', :foreign_key => 'primary_contact_id' belongs_to :number1_fan, :class_name => 'Person' + + has_many :agents_posts, :through => :agents, :source => :posts + has_many :agents_posts_authors, :through => :agents_posts, :source => :author scope :males, :conditions => { :gender => 'M' } scope :females, :conditions => { :gender => 'F' } diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index a3cb9c724a..f3b78c3647 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -46,6 +46,8 @@ class Post < ActiveRecord::Base has_one :very_special_comment_with_post, :class_name => "VerySpecialComment", :include => :post has_many :special_comments has_many :nonexistant_comments, :class_name => 'Comment', :conditions => 'comments.id < 0' + + has_many :special_comments_ratings, :through => :special_comments, :source => :ratings has_and_belongs_to_many :categories has_and_belongs_to_many :special_categories, :join_table => "categories_posts", :association_foreign_key => 'category_id' diff --git a/activerecord/test/models/rating.rb b/activerecord/test/models/rating.rb new file mode 100644 index 0000000000..12c4b5affa --- /dev/null +++ b/activerecord/test/models/rating.rb @@ -0,0 +1,3 @@ +class Rating < ActiveRecord::Base + belongs_to :comment +end diff --git a/activerecord/test/models/reference.rb b/activerecord/test/models/reference.rb index 4a17c936f5..2feb15d706 100644 --- a/activerecord/test/models/reference.rb +++ b/activerecord/test/models/reference.rb @@ -1,6 +1,8 @@ class Reference < ActiveRecord::Base belongs_to :person belongs_to :job + + has_many :agents_posts_authors, :through => :person end class BadReference < ActiveRecord::Base diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index dbd5da45eb..2fa9a4521e 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -449,6 +449,11 @@ ActiveRecord::Schema.define do t.string :type end + create_table :ratings, :force => true do |t| + t.integer :comment_id + t.integer :value + end + create_table :readers, :force => true do |t| t.integer :post_id, :null => false t.integer :person_id, :null => false -- cgit v1.2.3 From 7aea695815821df332913bae4b47714a525009a3 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 12 Oct 2010 13:33:51 +0100 Subject: A load of tests that need to be written --- .../nested_has_many_through_associations_test.rb | 63 ++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index ba75b70941..8a4ab627bb 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -28,6 +28,26 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase fixtures :authors, :books, :posts, :subscriptions, :subscribers, :tags, :taggings, :people, :readers, :references, :jobs, :ratings, :comments + # 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_a_has_many_through_association_on_source_reflection author = authors(:david) assert_equal [tags(:general), tags(:general)], author.tags @@ -41,6 +61,9 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert authors.empty? end + # has_many through + # Source: has_many + # Through: has_many through def test_has_many_through_a_has_many_through_association_on_through_reflection author = authors(:david) assert_equal [subscribers(:first), subscribers(:second), subscribers(:second)], author.subscribers @@ -49,6 +72,46 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase authors = Author.joins(:subscribers).where('subscribers.nick' => 'alterself') assert_equal [authors(:david)], authors end + + # TODO: has_many through + # Source: has_one through + # Through: has_one + + # TODO: has_many through + # Source: has_one + # Through: has_one through + + # TODO: has_many through + # Source: has_many through + # Through: has_one + + # TODO: has_many through + # Source: has_many + # Through: has_one through + + # TODO: has_many through + # Source: has_and_belongs_to_many + # Through: has_many + + # TODO: has_many through + # Source: has_many + # Through: has_and_belongs_to_many + + # TODO: has_many through + # Source: belongs_to + # Through: has_many through + + # TODO: has_many through + # Source: has_many through + # Through: belongs_to + + # TODO: has_one through + # Source: has_one through + # Through: has_one + + # TODO: has_one through + # Source: belongs_to + # Through: has_one through def test_distinct_has_many_through_a_has_many_through_association_on_source_reflection author = authors(:david) -- cgit v1.2.3 From 1777600e6e11e553ad97b7bc89e4b19e992eb3d3 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 12 Oct 2010 16:40:24 +0100 Subject: Support has_one through assocs as the source association --- .../nested_has_many_through_associations_test.rb | 35 ++++++++++++++++++++-- activerecord/test/fixtures/member_details.yml | 3 ++ activerecord/test/fixtures/members.yml | 2 ++ activerecord/test/fixtures/memberships.yml | 6 ++-- activerecord/test/fixtures/sponsors.yml | 9 ++++-- activerecord/test/models/member.rb | 5 +++- 6 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 activerecord/test/fixtures/member_details.yml (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 8a4ab627bb..4fab426696 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -18,6 +18,9 @@ require 'models/subscriber' require 'models/book' require 'models/subscription' require 'models/rating' +require 'models/member' +require 'models/member_detail' +require 'models/member_type' # NOTE: Some of these tests might not really test "nested" HMT associations, as opposed to ones which # are just one level deep. But it's all the same thing really, as the "nested" code is being @@ -26,7 +29,8 @@ require 'models/rating' class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase fixtures :authors, :books, :posts, :subscriptions, :subscribers, :tags, :taggings, - :people, :readers, :references, :jobs, :ratings, :comments + :people, :readers, :references, :jobs, :ratings, :comments, :members, :member_details, + :member_types # Through associations can either use the has_many or has_one macros. # @@ -56,6 +60,9 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase authors = Author.joins(:tags).where('tags.id' => tags(:general).id) assert_equal [authors(:david)], authors.uniq + authors = Author.includes(:tags) + assert_equal [tags(:general), tags(:general)], authors.first.tags + # This ensures that the polymorphism of taggings is being observed correctly authors = Author.joins(:tags).where('taggings.taggable_type' => 'FakeModel') assert authors.empty? @@ -71,11 +78,24 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase # All authors with subscribers where one of the subscribers' nick is 'alterself' authors = Author.joins(:subscribers).where('subscribers.nick' => 'alterself') assert_equal [authors(:david)], authors + + # TODO: Make this work + # authors = Author.includes(:subscribers) + # assert_equal [subscribers(:first), subscribers(:second), subscribers(:second)], authors.first.subscribers end - # TODO: has_many through + # has_many through # Source: has_one through # Through: has_one + def test_has_many_through_has_one_with_has_one_through_source_reflection + assert_equal [member_types(:founding)], members(:groucho).nested_member_types + + members = Member.joins(:nested_member_types).where('member_types.id' => member_types(:founding).id) + assert_equal [members(:groucho)], members + + members = Member.includes(:nested_member_types) + assert_equal [member_types(:founding)], members.first.nested_member_types + end # TODO: has_many through # Source: has_one @@ -105,9 +125,18 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase # Source: has_many through # Through: belongs_to - # TODO: has_one through + # 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 + + members = Member.joins(:nested_member_type).where('member_types.id' => member_types(:founding).id) + assert_equal [members(:groucho)], members + + members = Member.includes(:nested_member_type) + assert_equal member_types(:founding), members.first.nested_member_type + end # TODO: has_one through # Source: belongs_to diff --git a/activerecord/test/fixtures/member_details.yml b/activerecord/test/fixtures/member_details.yml new file mode 100644 index 0000000000..020932246a --- /dev/null +++ b/activerecord/test/fixtures/member_details.yml @@ -0,0 +1,3 @@ +groucho: + id: 1 + member_id: 1 diff --git a/activerecord/test/fixtures/members.yml b/activerecord/test/fixtures/members.yml index 6db945e61d..824840b7e5 100644 --- a/activerecord/test/fixtures/members.yml +++ b/activerecord/test/fixtures/members.yml @@ -1,6 +1,8 @@ groucho: + id: 1 name: Groucho Marx member_type_id: 1 some_other_guy: + id: 2 name: Englebert Humperdink member_type_id: 2 diff --git a/activerecord/test/fixtures/memberships.yml b/activerecord/test/fixtures/memberships.yml index b9722dbc8a..eed8b22af8 100644 --- a/activerecord/test/fixtures/memberships.yml +++ b/activerecord/test/fixtures/memberships.yml @@ -1,20 +1,20 @@ membership_of_boring_club: joined_on: <%= 3.weeks.ago.to_s(:db) %> club: boring_club - member: groucho + member_id: 1 favourite: false type: CurrentMembership membership_of_favourite_club: joined_on: <%= 3.weeks.ago.to_s(:db) %> club: moustache_club - member: groucho + member_id: 1 favourite: true type: Membership other_guys_membership: joined_on: <%= 4.weeks.ago.to_s(:db) %> club: boring_club - member: some_other_guy + member_id: 2 favourite: false type: CurrentMembership diff --git a/activerecord/test/fixtures/sponsors.yml b/activerecord/test/fixtures/sponsors.yml index 42df8957d1..bfc6b238b1 100644 --- a/activerecord/test/fixtures/sponsors.yml +++ b/activerecord/test/fixtures/sponsors.yml @@ -1,9 +1,12 @@ moustache_club_sponsor_for_groucho: sponsor_club: moustache_club - sponsorable: groucho (Member) + sponsorable_id: 1 + sponsorable_type: Member boring_club_sponsor_for_groucho: sponsor_club: boring_club - sponsorable: some_other_guy (Member) + sponsorable_id: 2 + sponsorable_type: Member crazy_club_sponsor_for_groucho: sponsor_club: crazy_club - sponsorable: some_other_guy (Member) \ No newline at end of file + sponsorable_id: 2 + sponsorable_type: Member diff --git a/activerecord/test/models/member.rb b/activerecord/test/models/member.rb index 255fb569d7..b8b22d0fde 100644 --- a/activerecord/test/models/member.rb +++ b/activerecord/test/models/member.rb @@ -9,4 +9,7 @@ class Member < ActiveRecord::Base has_one :member_detail has_one :organization, :through => :member_detail belongs_to :member_type -end \ No newline at end of file + + has_many :nested_member_types, :through => :member_detail, :source => :member_type + has_one :nested_member_type, :through => :member_detail, :source => :member_type +end -- cgit v1.2.3 From 6a016a551109ed2ef78fff8f74aef6b1f4ae96a9 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 12 Oct 2010 16:53:22 +0100 Subject: Add test_has_many_through_has_one_through --- .../nested_has_many_through_associations_test.rb | 16 ++++++++++++++-- activerecord/test/models/member.rb | 3 +++ 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 4fab426696..c1e8a4b1bf 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -21,6 +21,8 @@ require 'models/rating' require 'models/member' require 'models/member_detail' require 'models/member_type' +require 'models/sponsor' +require 'models/club' # NOTE: Some of these tests might not really test "nested" HMT associations, as opposed to ones which # are just one level deep. But it's all the same thing really, as the "nested" code is being @@ -30,7 +32,7 @@ require 'models/member_type' class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase fixtures :authors, :books, :posts, :subscriptions, :subscribers, :tags, :taggings, :people, :readers, :references, :jobs, :ratings, :comments, :members, :member_details, - :member_types + :member_types, :sponsors, :clubs # Through associations can either use the has_many or has_one macros. # @@ -97,9 +99,19 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal [member_types(:founding)], members.first.nested_member_types end - # TODO: has_many through + # has_many through # Source: has_one # Through: has_one through + def test_has_many_through_has_one_through + assert_equal [sponsors(:moustache_club_sponsor_for_groucho)], members(:groucho).nested_sponsors + + members = Member.joins(:nested_sponsors).where('sponsors.id' => sponsors(:moustache_club_sponsor_for_groucho).id) + assert_equal [members(:groucho)], members + + # TODO: Make this work + # members = Member.includes(:nested_sponsors) + # assert_equal [sponsors(:moustache_club_sponsor_for_groucho)], members.first.nested_sponsors + end # TODO: has_many through # Source: has_many through diff --git a/activerecord/test/models/member.rb b/activerecord/test/models/member.rb index b8b22d0fde..c2dd9efe3b 100644 --- a/activerecord/test/models/member.rb +++ b/activerecord/test/models/member.rb @@ -12,4 +12,7 @@ class Member < ActiveRecord::Base has_many :nested_member_types, :through => :member_detail, :source => :member_type has_one :nested_member_type, :through => :member_detail, :source => :member_type + + has_many :nested_sponsors, :through => :sponsor_club, :source => :sponsor + has_one :nested_sponsor, :through => :sponsor_club, :source => :sponsor end -- cgit v1.2.3 From 61073861856110b4a842a4d5e1033698fd52901f Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 12 Oct 2010 16:54:43 +0100 Subject: Rename some tests for consistency --- .../cases/associations/nested_has_many_through_associations_test.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index c1e8a4b1bf..bc0fb8582d 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -54,7 +54,7 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase # has_many through # Source: has_many through # Through: has_many - def test_has_many_through_a_has_many_through_association_on_source_reflection + def test_has_many_through_has_many_with_has_many_through_source_reflection author = authors(:david) assert_equal [tags(:general), tags(:general)], author.tags @@ -73,7 +73,7 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase # has_many through # Source: has_many # Through: has_many through - def test_has_many_through_a_has_many_through_association_on_through_reflection + def test_has_many_through_has_many_through_with_has_many_source_reflection author = authors(:david) assert_equal [subscribers(:first), subscribers(:second), subscribers(:second)], author.subscribers @@ -102,7 +102,7 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase # has_many through # Source: has_one # Through: has_one through - def test_has_many_through_has_one_through + def test_has_many_through_has_one_through_with_has_one_source_reflection assert_equal [sponsors(:moustache_club_sponsor_for_groucho)], members(:groucho).nested_sponsors members = Member.joins(:nested_sponsors).where('sponsors.id' => sponsors(:moustache_club_sponsor_for_groucho).id) -- cgit v1.2.3 From dc39aceb94fa810f8d7e263c0293f325fbf9a109 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 12 Oct 2010 17:27:10 +0100 Subject: Adding test_has_many_through_has_one_with_has_many_through_source_reflection and modifying ThroughAssociationScope to make it work correctly. --- .../nested_has_many_through_associations_test.rb | 21 +++++++++++++++++++-- activerecord/test/fixtures/member_details.yml | 5 +++++ activerecord/test/models/member.rb | 2 ++ activerecord/test/models/member_detail.rb | 2 ++ 4 files changed, 28 insertions(+), 2 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index bc0fb8582d..4b5ce6313a 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -23,6 +23,7 @@ require 'models/member_detail' require 'models/member_type' require 'models/sponsor' require 'models/club' +require 'models/organization' # NOTE: Some of these tests might not really test "nested" HMT associations, as opposed to ones which # are just one level deep. But it's all the same thing really, as the "nested" code is being @@ -32,7 +33,7 @@ require 'models/club' class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase fixtures :authors, :books, :posts, :subscriptions, :subscribers, :tags, :taggings, :people, :readers, :references, :jobs, :ratings, :comments, :members, :member_details, - :member_types, :sponsors, :clubs + :member_types, :sponsors, :clubs, :organizations # Through associations can either use the has_many or has_one macros. # @@ -113,9 +114,25 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase # assert_equal [sponsors(:moustache_club_sponsor_for_groucho)], members.first.nested_sponsors end - # TODO: has_many through + # has_many through # Source: has_many through # Through: has_one + def test_has_many_through_has_one_with_has_many_through_source_reflection + assert_equal [member_details(:groucho), member_details(:some_other_guy)], + members(:groucho).organization_member_details + + members = Member.joins(:organization_member_details). + where('member_details.id' => member_details(:groucho).id) + assert_equal [members(:groucho), members(:some_other_guy)], members + + members = Member.joins(:organization_member_details). + where('member_details.id' => 9) + assert members.empty? + + members = Member.includes(:organization_member_details) + assert_equal [member_details(:groucho), member_details(:some_other_guy)], + members.first.organization_member_details + end # TODO: has_many through # Source: has_many diff --git a/activerecord/test/fixtures/member_details.yml b/activerecord/test/fixtures/member_details.yml index 020932246a..e1fe695a9b 100644 --- a/activerecord/test/fixtures/member_details.yml +++ b/activerecord/test/fixtures/member_details.yml @@ -1,3 +1,8 @@ groucho: id: 1 member_id: 1 + organization: nsa +some_other_guy: + id: 2 + member_id: 2 + organization: nsa diff --git a/activerecord/test/models/member.rb b/activerecord/test/models/member.rb index c2dd9efe3b..1113ef3e28 100644 --- a/activerecord/test/models/member.rb +++ b/activerecord/test/models/member.rb @@ -15,4 +15,6 @@ class Member < ActiveRecord::Base has_many :nested_sponsors, :through => :sponsor_club, :source => :sponsor has_one :nested_sponsor, :through => :sponsor_club, :source => :sponsor + + has_many :organization_member_details, :through => :member_detail end diff --git a/activerecord/test/models/member_detail.rb b/activerecord/test/models/member_detail.rb index 94f59e5794..0f53b69ced 100644 --- a/activerecord/test/models/member_detail.rb +++ b/activerecord/test/models/member_detail.rb @@ -2,4 +2,6 @@ class MemberDetail < ActiveRecord::Base belongs_to :member belongs_to :organization has_one :member_type, :through => :member + + has_many :organization_member_details, :through => :organization, :source => :member_details end -- cgit v1.2.3 From 56064aa4b014233ae54413628679b7f7fa5d6f77 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 12 Oct 2010 17:32:52 +0100 Subject: Add test_has_many_through_has_one_through_with_has_many_source_reflection --- .../nested_has_many_through_associations_test.rb | 19 ++++++++++++++++++- activerecord/test/models/member.rb | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 4b5ce6313a..7c4bffaddd 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -134,9 +134,26 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase members.first.organization_member_details end - # TODO: has_many through + # has_many through # Source: has_many # Through: has_one through + def test_has_many_through_has_one_through_with_has_many_source_reflection + assert_equal [member_details(:groucho), member_details(:some_other_guy)], + members(:groucho).organization_member_details_2 + + members = Member.joins(:organization_member_details_2). + where('member_details.id' => member_details(:groucho).id) + assert_equal [members(:groucho), members(:some_other_guy)], members + + members = Member.joins(:organization_member_details_2). + where('member_details.id' => 9) + assert members.empty? + + # TODO: Make this work + # members = Member.includes(:organization_member_details_2) + # assert_equal [member_details(:groucho), member_details(:some_other_guy)], + # members.first.organization_member_details_2 + end # TODO: has_many through # Source: has_and_belongs_to_many diff --git a/activerecord/test/models/member.rb b/activerecord/test/models/member.rb index 1113ef3e28..44c10cc4a4 100644 --- a/activerecord/test/models/member.rb +++ b/activerecord/test/models/member.rb @@ -17,4 +17,5 @@ class Member < ActiveRecord::Base has_one :nested_sponsor, :through => :sponsor_club, :source => :sponsor has_many :organization_member_details, :through => :member_detail + has_many :organization_member_details_2, :through => :organization, :source => :member_details end -- cgit v1.2.3 From c37a5e7acde436b359043a67b7daace8be6f08c6 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 12 Oct 2010 18:16:31 +0100 Subject: Add a commented, failing test for using a habtm in a has many through association. I want to refactor how aliasing works first. --- .../associations/has_and_belongs_to_many_associations_test.rb | 8 ++++---- .../associations/nested_has_many_through_associations_test.rb | 9 +++++++-- activerecord/test/fixtures/categories_posts.yml | 8 ++++++++ activerecord/test/models/author.rb | 8 +++++--- 4 files changed, 24 insertions(+), 9 deletions(-) (limited to 'activerecord/test') 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..e67cbcc1a8 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,13 +713,13 @@ 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 1, categories(:technology).posts_grouped_by_title.size + assert_equal 5, categories(:general).posts_grouped_by_title.size + assert_equal 2, categories(:technology).posts_grouped_by_title.size end def test_find_scoped_grouped_having diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 7c4bffaddd..835a573978 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -24,6 +24,7 @@ require 'models/member_type' require 'models/sponsor' require 'models/club' require 'models/organization' +require 'models/category' # NOTE: Some of these tests might not really test "nested" HMT associations, as opposed to ones which # are just one level deep. But it's all the same thing really, as the "nested" code is being @@ -33,7 +34,7 @@ require 'models/organization' class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase fixtures :authors, :books, :posts, :subscriptions, :subscribers, :tags, :taggings, :people, :readers, :references, :jobs, :ratings, :comments, :members, :member_details, - :member_types, :sponsors, :clubs, :organizations + :member_types, :sponsors, :clubs, :organizations, :categories, :categories_posts # Through associations can either use the has_many or has_one macros. # @@ -155,9 +156,13 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase # members.first.organization_member_details_2 end - # TODO: has_many through + # has_many through # Source: has_and_belongs_to_many # Through: has_many + # TODO: Enable and implement this, and finish off the test + # def test_has_many_through_has_many_with_has_and_belongs_to_many_source_reflection + # assert_equal [categories(:general), categories(:technology)], authors(:bob).post_categories + # end # TODO: has_many through # Source: has_many diff --git a/activerecord/test/fixtures/categories_posts.yml b/activerecord/test/fixtures/categories_posts.yml index 9b67ab4fa4..3b41510cb1 100644 --- a/activerecord/test/fixtures/categories_posts.yml +++ b/activerecord/test/fixtures/categories_posts.yml @@ -21,3 +21,11 @@ sti_test_sti_habtm: general_hello: category_id: 1 post_id: 4 + +general_misc_by_bob: + category_id: 1 + post_id: 8 + +technology_misc_by_bob: + category_id: 2 + post_id: 8 diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index 1fbd729b60..584164f19a 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -83,9 +83,9 @@ class Author < ActiveRecord::Base has_many :author_favorites has_many :favorite_authors, :through => :author_favorites, :order => 'name' - has_many :tagging, :through => :posts # through polymorphic has_one - has_many :taggings, :through => :posts # through polymorphic has_many - has_many :tags, :through => :posts # through has_many :through (on source reflection + polymorphic) + has_many :tagging, :through => :posts + has_many :taggings, :through => :posts + has_many :tags, :through => :posts has_many :similar_posts, :through => :tags, :source => :tagged_posts has_many :distinct_tags, :through => :posts, :source => :tags, :select => "DISTINCT tags.*", :order => "tags.name" has_many :post_categories, :through => :posts, :source => :categories @@ -100,6 +100,8 @@ class Author < ActiveRecord::Base belongs_to :author_address, :dependent => :destroy belongs_to :author_address_extra, :dependent => :delete, :class_name => "AuthorAddress" + has_many :post_categories, :through => :posts, :source => :categories + scope :relation_include_posts, includes(:posts) scope :relation_include_tags, includes(:tags) -- cgit v1.2.3 From 781ad0f8fee209bcf10c5e52daae246477d49ea7 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Wed, 13 Oct 2010 01:29:09 +0100 Subject: First bit of support for habtm in through assocs - test_has_many_through_has_many_with_has_and_belongs_to_many_source_reflection now passes --- .../has_and_belongs_to_many_associations_test.rb | 2 +- .../nested_has_many_through_associations_test.rb | 13 +++++++++---- activerecord/test/fixtures/categories.yml | 5 +++++ activerecord/test/fixtures/categories_posts.yml | 4 ++-- 4 files changed, 17 insertions(+), 7 deletions(-) (limited to 'activerecord/test') 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 e67cbcc1a8..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 @@ -719,7 +719,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_find_scoped_grouped assert_equal 5, categories(:general).posts_grouped_by_title.size - assert_equal 2, categories(:technology).posts_grouped_by_title.size + assert_equal 1, categories(:technology).posts_grouped_by_title.size end def test_find_scoped_grouped_having diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 835a573978..964112b006 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -159,10 +159,15 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase # has_many through # Source: has_and_belongs_to_many # Through: has_many - # TODO: Enable and implement this, and finish off the test - # def test_has_many_through_has_many_with_has_and_belongs_to_many_source_reflection - # assert_equal [categories(:general), categories(:technology)], authors(:bob).post_categories - # end + def test_has_many_through_has_many_with_has_and_belongs_to_many_source_reflection + assert_equal [categories(:general), categories(:cooking)], authors(:bob).post_categories + + authors = Author.joins(:post_categories).where('categories.id' => categories(:cooking).id) + assert_equal [authors(:bob)], authors + + authors = Author.includes(:post_categories) + assert_equal [categories(:general), categories(:cooking)], authors[2].post_categories + end # TODO: has_many through # Source: has_many diff --git a/activerecord/test/fixtures/categories.yml b/activerecord/test/fixtures/categories.yml index b0770a093d..3e75e733a6 100644 --- a/activerecord/test/fixtures/categories.yml +++ b/activerecord/test/fixtures/categories.yml @@ -12,3 +12,8 @@ sti_test: id: 3 name: Special category type: SpecialCategory + +cooking: + id: 4 + name: Cooking + type: Category diff --git a/activerecord/test/fixtures/categories_posts.yml b/activerecord/test/fixtures/categories_posts.yml index 3b41510cb1..c6f0d885f5 100644 --- a/activerecord/test/fixtures/categories_posts.yml +++ b/activerecord/test/fixtures/categories_posts.yml @@ -26,6 +26,6 @@ general_misc_by_bob: category_id: 1 post_id: 8 -technology_misc_by_bob: - category_id: 2 +cooking_misc_by_bob: + category_id: 4 post_id: 8 -- cgit v1.2.3 From 212fdd8ba9624f61421a7a950283537a3d39ac18 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Wed, 13 Oct 2010 18:36:51 +0100 Subject: Add test_has_many_through_has_and_belongs_to_many_with_has_many_source_reflection and make it work --- .../nested_has_many_through_associations_test.rb | 12 +++++++++++- activerecord/test/models/category.rb | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 964112b006..4e7e766b14 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -169,9 +169,19 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal [categories(:general), categories(:cooking)], authors[2].post_categories end - # TODO: has_many through + # 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 + assert_equal [comments(:greetings), comments(:more_greetings)], categories(:technology).post_comments + + categories = Category.joins(:post_comments).where('comments.id' => comments(:more_greetings).id) + assert_equal [categories(:general), categories(:technology)], categories + + # TODO: Make this work + # categories = Category.includes(:post_comments) + # assert_equal [comments(:greetings), comments(:more_greetings)], categories[1].post_comments + end # TODO: has_many through # Source: belongs_to diff --git a/activerecord/test/models/category.rb b/activerecord/test/models/category.rb index 48415846dd..c933943813 100644 --- a/activerecord/test/models/category.rb +++ b/activerecord/test/models/category.rb @@ -23,6 +23,8 @@ class Category < ActiveRecord::Base has_many :categorizations has_many :authors, :through => :categorizations, :select => 'authors.*, categorizations.post_id' + + has_many :post_comments, :through => :posts, :source => :comments end class SpecialCategory < Category -- cgit v1.2.3 From bc821a56114ae6f6d0b595475ad9e71f01f46f35 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Thu, 14 Oct 2010 12:59:16 +0100 Subject: Added test_has_many_through_has_many_with_has_many_through_habtm_source_reflection and make it pass --- activerecord/test/cases/associations/join_model_test.rb | 2 +- .../nested_has_many_through_associations_test.rb | 17 ++++++++++++++++- activerecord/test/fixtures/categorizations.yml | 6 ++++++ activerecord/test/models/author.rb | 1 + 4 files changed, 24 insertions(+), 2 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index 4b7a8b494d..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 diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 4e7e766b14..26c31ef761 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -25,6 +25,7 @@ require 'models/sponsor' require 'models/club' require 'models/organization' require 'models/category' +require 'models/categorization' # NOTE: Some of these tests might not really test "nested" HMT associations, as opposed to ones which # are just one level deep. But it's all the same thing really, as the "nested" code is being @@ -34,7 +35,8 @@ require 'models/category' class NestedHasManyThroughAssociationsTest < 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 + :member_types, :sponsors, :clubs, :organizations, :categories, :categories_posts, + :categorizations # Through associations can either use the has_many or has_one macros. # @@ -183,6 +185,19 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase # assert_equal [comments(:greetings), comments(:more_greetings)], categories[1].post_comments 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 + assert_equal [comments(:greetings), comments(:more_greetings)], authors(:bob).category_post_comments + + authors = Author.joins(:category_post_comments).where('comments.id' => comments(:does_it_hurt).id) + assert_equal [authors(:david), authors(:mary)], authors + + comments = Author.joins(:category_post_comments) + assert_equal [comments(:greetings), comments(:more_greetings)], comments[2].category_post_comments + end + # TODO: has_many through # Source: belongs_to # Through: has_many through diff --git a/activerecord/test/fixtures/categorizations.yml b/activerecord/test/fixtures/categorizations.yml index c5b6fc9a51..62e5bd111a 100644 --- a/activerecord/test/fixtures/categorizations.yml +++ b/activerecord/test/fixtures/categorizations.yml @@ -15,3 +15,9 @@ mary_thinking_general: author_id: 2 post_id: 2 category_id: 1 + +bob_misc_by_bob_technology: + id: 4 + author_id: 3 + post_id: 8 + category_id: 2 diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index 584164f19a..f2f373af8c 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -101,6 +101,7 @@ class Author < ActiveRecord::Base belongs_to :author_address_extra, :dependent => :delete, :class_name => "AuthorAddress" has_many :post_categories, :through => :posts, :source => :categories + has_many :category_post_comments, :through => :categories, :source => :post_comments scope :relation_include_posts, includes(:posts) scope :relation_include_tags, includes(:tags) -- cgit v1.2.3 From 7963c30ebaeb511f7ddacc99ae2c7a530059ae6b Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Thu, 14 Oct 2010 13:07:28 +0100 Subject: Add test_has_many_through_has_many_through_with_belongs_to_source_reflection (which already works) --- .../nested_has_many_through_associations_test.rb | 13 ++++++++++++- activerecord/test/models/author.rb | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 26c31ef761..7e1fc60cb9 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -198,9 +198,20 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal [comments(:greetings), comments(:more_greetings)], comments[2].category_post_comments end - # TODO: has_many through + # has_many through # Source: belongs_to # Through: has_many through + def test_has_many_through_has_many_through_with_belongs_to_source_reflection + author = authors(:david) + assert_equal [tags(:general), tags(:general)], author.tagging_tags + + authors = Author.joins(:tagging_tags).where('tags.id' => tags(:general).id) + assert_equal [authors(:david)], authors.uniq + + # TODO: Make this work + # authors = Author.includes(:tagging_tags) + # assert_equal [tags(:general), tags(:general)], authors.first.tagging_tags + end # TODO: has_many through # Source: has_many through diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index f2f373af8c..b5f702018a 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -89,6 +89,7 @@ class Author < ActiveRecord::Base has_many :similar_posts, :through => :tags, :source => :tagged_posts has_many :distinct_tags, :through => :posts, :source => :tags, :select => "DISTINCT tags.*", :order => "tags.name" has_many :post_categories, :through => :posts, :source => :categories + has_many :tagging_tags, :through => :taggings, :source => :tag has_many :books has_many :subscriptions, :through => :books -- cgit v1.2.3 From 25acd19da5f75a425218740fbb187b18bbb060ce Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Thu, 14 Oct 2010 13:16:47 +0100 Subject: Add test_has_many_through_belongs_to_with_has_many_through_source_reflection (which already passes) --- .../nested_has_many_through_associations_test.rb | 13 ++++++++++++- activerecord/test/models/categorization.rb | 4 +++- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 7e1fc60cb9..6212eed0eb 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -213,9 +213,20 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase # assert_equal [tags(:general), tags(:general)], authors.first.tagging_tags end - # TODO: has_many through + # has_many through # Source: has_many through # Through: belongs_to + def test_has_many_through_belongs_to_with_has_many_through_source_reflection + assert_equal [taggings(:welcome_general), taggings(:thinking_general)], + categorizations(:david_welcome_general).post_taggings + + categorizations = Categorization.joins(:post_taggings).where('taggings.id' => taggings(:welcome_general).id) + assert_equal [categorizations(:david_welcome_general)], categorizations + + categorizations = Categorization.includes(:post_taggings) + assert_equal [taggings(:welcome_general), taggings(:thinking_general)], + categorizations.first.post_taggings + end # has_one through # Source: has_one through diff --git a/activerecord/test/models/categorization.rb b/activerecord/test/models/categorization.rb index 10594323ff..bddc1e5f0c 100644 --- a/activerecord/test/models/categorization.rb +++ b/activerecord/test/models/categorization.rb @@ -2,4 +2,6 @@ class Categorization < ActiveRecord::Base belongs_to :post belongs_to :category belongs_to :author -end \ No newline at end of file + + has_many :post_taggings, :through => :author, :source => :taggings +end -- cgit v1.2.3 From 002985fb66ae63f157db84f83520c3c256c04f77 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Thu, 14 Oct 2010 13:44:32 +0100 Subject: Add test_has_one_through_has_one_through_with_belongs_to_source_reflection --- .../nested_has_many_through_associations_test.rb | 15 +++++++++++++-- activerecord/test/fixtures/clubs.yml | 4 +++- activerecord/test/fixtures/members.yml | 3 +++ activerecord/test/fixtures/memberships.yml | 7 +++++++ activerecord/test/models/club.rb | 3 ++- activerecord/test/models/member.rb | 2 ++ activerecord/test/schema/schema.rb | 1 + 7 files changed, 31 insertions(+), 4 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 6212eed0eb..0bd19c10e0 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -26,6 +26,7 @@ require 'models/club' require 'models/organization' require 'models/category' require 'models/categorization' +require 'models/membership' # NOTE: Some of these tests might not really test "nested" HMT associations, as opposed to ones which # are just one level deep. But it's all the same thing really, as the "nested" code is being @@ -36,7 +37,7 @@ class NestedHasManyThroughAssociationsTest < 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 + :categorizations, :memberships # Through associations can either use the has_many or has_one macros. # @@ -241,9 +242,19 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal member_types(:founding), members.first.nested_member_type end - # TODO: has_one through + # 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 + + members = Member.joins(:club_category).where('categories.id' => categories(:technology).id) + assert_equal [members(:blarpy_winkup)], members + + # TODO: Make this work + # members = Member.includes(:club_category) + # assert_equal categories(:general), members.first.club_category + end def test_distinct_has_many_through_a_has_many_through_association_on_source_reflection author = authors(:david) diff --git a/activerecord/test/fixtures/clubs.yml b/activerecord/test/fixtures/clubs.yml index 1986d28229..82e439e8e5 100644 --- a/activerecord/test/fixtures/clubs.yml +++ b/activerecord/test/fixtures/clubs.yml @@ -1,6 +1,8 @@ boring_club: name: Banana appreciation society + category_id: 1 moustache_club: name: Moustache and Eyebrow Fancier Club crazy_club: - name: Skull and bones \ No newline at end of file + name: Skull and bones + category_id: 2 diff --git a/activerecord/test/fixtures/members.yml b/activerecord/test/fixtures/members.yml index 824840b7e5..f3bbf0dac6 100644 --- a/activerecord/test/fixtures/members.yml +++ b/activerecord/test/fixtures/members.yml @@ -6,3 +6,6 @@ some_other_guy: id: 2 name: Englebert Humperdink member_type_id: 2 +blarpy_winkup: + id: 3 + name: Blarpy Winkup diff --git a/activerecord/test/fixtures/memberships.yml b/activerecord/test/fixtures/memberships.yml index eed8b22af8..60eb641054 100644 --- a/activerecord/test/fixtures/memberships.yml +++ b/activerecord/test/fixtures/memberships.yml @@ -18,3 +18,10 @@ other_guys_membership: member_id: 2 favourite: false type: CurrentMembership + +blarpy_winkup_crazy_club: + joined_on: <%= 4.weeks.ago.to_s(:db) %> + club: crazy_club + member_id: 3 + favourite: false + type: CurrentMembership diff --git a/activerecord/test/models/club.rb b/activerecord/test/models/club.rb index 6e7cdd643a..83d6b1b15a 100644 --- a/activerecord/test/models/club.rb +++ b/activerecord/test/models/club.rb @@ -4,10 +4,11 @@ class Club < ActiveRecord::Base has_many :current_memberships has_one :sponsor has_one :sponsored_member, :through => :sponsor, :source => :sponsorable, :source_type => "Member" + belongs_to :category private def private_method "I'm sorry sir, this is a *private* club, not a *pirate* club" end -end \ No newline at end of file +end diff --git a/activerecord/test/models/member.rb b/activerecord/test/models/member.rb index 44c10cc4a4..bed62f8b7f 100644 --- a/activerecord/test/models/member.rb +++ b/activerecord/test/models/member.rb @@ -18,4 +18,6 @@ class Member < ActiveRecord::Base has_many :organization_member_details, :through => :member_detail has_many :organization_member_details_2, :through => :organization, :source => :member_details + + has_one :club_category, :through => :club, :source => :category end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 2fa9a4521e..8b9c56b895 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -113,6 +113,7 @@ ActiveRecord::Schema.define do create_table :clubs, :force => true do |t| t.string :name + t.integer :category_id end create_table :collections, :force => true do |t| -- cgit v1.2.3 From 11508db1be0016bb1a9893c7b2062845233f78e0 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Thu, 14 Oct 2010 13:52:38 +0100 Subject: Remove unnecessary requires from nested_has_many_through_associations_test.rb --- .../cases/associations/nested_has_many_through_associations_test.rb | 6 ------ 1 file changed, 6 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 0bd19c10e0..eea1c4e54c 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -8,12 +8,6 @@ require 'models/reader' require 'models/comment' require 'models/tag' require 'models/tagging' -require 'models/owner' -require 'models/pet' -require 'models/toy' -require 'models/contract' -require 'models/company' -require 'models/developer' require 'models/subscriber' require 'models/book' require 'models/subscription' -- cgit v1.2.3 From 06c64eb60611bdeeb55e35a4819ba65d74dbadc3 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Fri, 15 Oct 2010 15:46:19 +0100 Subject: Support preloading nested through associations (using the default multi-query strategy) --- .../nested_has_many_through_associations_test.rb | 201 ++++++++++++++------- 1 file changed, 140 insertions(+), 61 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index eea1c4e54c..32b03bf076 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -54,70 +54,98 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase # Source: has_many through # Through: has_many def test_has_many_through_has_many_with_has_many_through_source_reflection - author = authors(:david) - assert_equal [tags(:general), tags(:general)], author.tags + general = tags(:general) + + assert_equal [general, general], authors(:david).tags # Only David has a Post tagged with General authors = Author.joins(:tags).where('tags.id' => tags(:general).id) assert_equal [authors(:david)], authors.uniq - authors = Author.includes(:tags) - assert_equal [tags(:general), tags(:general)], authors.first.tags - # This ensures that the polymorphism of taggings is being observed correctly authors = Author.joins(:tags).where('taggings.taggable_type' => 'FakeModel') assert authors.empty? + + assert_queries(5) do + authors = Author.includes(:tags).to_a + end + + 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 [subscribers(:first), subscribers(:second), subscribers(:second)], author.subscribers + assert_equal [luke, david, david], author.subscribers # All authors with subscribers where one of the subscribers' nick is 'alterself' authors = Author.joins(:subscribers).where('subscribers.nick' => 'alterself') assert_equal [authors(:david)], authors - # TODO: Make this work - # authors = Author.includes(:subscribers) - # assert_equal [subscribers(:first), subscribers(:second), subscribers(:second)], authors.first.subscribers + assert_queries(4) do + authors = Author.includes(:subscribers).to_a + end + + assert_no_queries do + assert_equal [luke, david, david], authors.first.subscribers.sort_by(&:nick) + end + + # TODO: Add eager loading test using LEFT OUTER JOIN end # has_many through # Source: has_one through # Through: has_one def test_has_many_through_has_one_with_has_one_through_source_reflection - assert_equal [member_types(:founding)], members(:groucho).nested_member_types + founding = member_types(:founding) + + assert_equal [founding], members(:groucho).nested_member_types - members = Member.joins(:nested_member_types).where('member_types.id' => member_types(:founding).id) + members = Member.joins(:nested_member_types).where('member_types.id' => founding.id) assert_equal [members(:groucho)], members - members = Member.includes(:nested_member_types) - assert_equal [member_types(:founding)], members.first.nested_member_types + assert_queries(4) do + members = Member.includes(:nested_member_types).to_a + end + + 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 - assert_equal [sponsors(:moustache_club_sponsor_for_groucho)], members(:groucho).nested_sponsors + mustache = sponsors(:moustache_club_sponsor_for_groucho) - members = Member.joins(:nested_sponsors).where('sponsors.id' => sponsors(:moustache_club_sponsor_for_groucho).id) + assert_equal [mustache], members(:groucho).nested_sponsors + + members = Member.joins(:nested_sponsors).where('sponsors.id' => mustache.id) assert_equal [members(:groucho)], members - # TODO: Make this work - # members = Member.includes(:nested_sponsors) - # assert_equal [sponsors(:moustache_club_sponsor_for_groucho)], members.first.nested_sponsors + assert_queries(4) do + members = Member.includes(:nested_sponsors).to_a + end + + 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 - assert_equal [member_details(:groucho), member_details(:some_other_guy)], - members(:groucho).organization_member_details + groucho_details, other_details = member_details(:groucho), member_details(:some_other_guy) + + assert_equal [groucho_details, other_details], members(:groucho).organization_member_details members = Member.joins(:organization_member_details). where('member_details.id' => member_details(:groucho).id) @@ -127,127 +155,178 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase where('member_details.id' => 9) assert members.empty? - members = Member.includes(:organization_member_details) - assert_equal [member_details(:groucho), member_details(:some_other_guy)], - members.first.organization_member_details + assert_queries(4) do + members = Member.includes(:organization_member_details).to_a + end + + assert_no_queries do + assert_equal [groucho_details, other_details], members.first.organization_member_details + 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 - assert_equal [member_details(:groucho), member_details(:some_other_guy)], - members(:groucho).organization_member_details_2 + groucho_details, other_details = member_details(:groucho), member_details(:some_other_guy) + + assert_equal [groucho_details, other_details], members(:groucho).organization_member_details_2 members = Member.joins(:organization_member_details_2). - where('member_details.id' => member_details(:groucho).id) + where('member_details.id' => groucho_details.id) assert_equal [members(:groucho), members(:some_other_guy)], members members = Member.joins(:organization_member_details_2). where('member_details.id' => 9) assert members.empty? - # TODO: Make this work - # members = Member.includes(:organization_member_details_2) - # assert_equal [member_details(:groucho), member_details(:some_other_guy)], - # members.first.organization_member_details_2 + assert_queries(4) do + members = Member.includes(:organization_member_details_2).to_a + end + + assert_no_queries do + assert_equal [groucho_details, other_details], members.first.organization_member_details_2 + 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 - assert_equal [categories(:general), categories(:cooking)], authors(:bob).post_categories + general, cooking = categories(:general), categories(:cooking) + + assert_equal [general, cooking], authors(:bob).post_categories - authors = Author.joins(:post_categories).where('categories.id' => categories(:cooking).id) + authors = Author.joins(:post_categories).where('categories.id' => cooking.id) assert_equal [authors(:bob)], authors - authors = Author.includes(:post_categories) - assert_equal [categories(:general), categories(:cooking)], authors[2].post_categories + assert_queries(3) do + authors = Author.includes(:post_categories).to_a + end + + assert_no_queries do + assert_equal [general, cooking], authors[2].post_categories + 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 - assert_equal [comments(:greetings), comments(:more_greetings)], categories(:technology).post_comments + greetings, more = comments(:greetings), comments(:more_greetings) + + assert_equal [greetings, more], categories(:technology).post_comments - categories = Category.joins(:post_comments).where('comments.id' => comments(:more_greetings).id) + categories = Category.joins(:post_comments).where('comments.id' => more.id) assert_equal [categories(:general), categories(:technology)], categories - # TODO: Make this work - # categories = Category.includes(:post_comments) - # assert_equal [comments(:greetings), comments(:more_greetings)], categories[1].post_comments + assert_queries(3) do + categories = Category.includes(:post_comments).to_a + end + + assert_no_queries do + assert_equal [greetings, more], categories[1].post_comments + 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 - assert_equal [comments(:greetings), comments(:more_greetings)], authors(:bob).category_post_comments + greetings, more = comments(:greetings), comments(:more_greetings) + + assert_equal [greetings, more], authors(:bob).category_post_comments authors = Author.joins(:category_post_comments).where('comments.id' => comments(:does_it_hurt).id) assert_equal [authors(:david), authors(:mary)], authors - comments = Author.joins(:category_post_comments) - assert_equal [comments(:greetings), comments(:more_greetings)], comments[2].category_post_comments + assert_queries(5) do + authors = Author.includes(:category_post_comments).to_a + end + + assert_no_queries do + assert_equal [greetings, more], authors[2].category_post_comments + 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 - author = authors(:david) - assert_equal [tags(:general), tags(:general)], author.tagging_tags + general = tags(:general) + + assert_equal [general, general], authors(:david).tagging_tags authors = Author.joins(:tagging_tags).where('tags.id' => tags(:general).id) assert_equal [authors(:david)], authors.uniq - # TODO: Make this work - # authors = Author.includes(:tagging_tags) - # assert_equal [tags(:general), tags(:general)], authors.first.tagging_tags + assert_queries(5) do + authors = Author.includes(:tagging_tags).to_a + end + + 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 - assert_equal [taggings(:welcome_general), taggings(:thinking_general)], - categorizations(:david_welcome_general).post_taggings + welcome_general, thinking_general = taggings(:welcome_general), taggings(:thinking_general) + + assert_equal [welcome_general, thinking_general], categorizations(:david_welcome_general).post_taggings - categorizations = Categorization.joins(:post_taggings).where('taggings.id' => taggings(:welcome_general).id) + categorizations = Categorization.joins(:post_taggings).where('taggings.id' => welcome_general.id) assert_equal [categorizations(:david_welcome_general)], categorizations - categorizations = Categorization.includes(:post_taggings) - assert_equal [taggings(:welcome_general), taggings(:thinking_general)], - categorizations.first.post_taggings + assert_queries(4) do + categorizations = Categorization.includes(:post_taggings).to_a + end + + assert_no_queries do + assert_equal [welcome_general, thinking_general], categorizations.first.post_taggings + 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 - assert_equal member_types(:founding), members(:groucho).nested_member_type + founding = member_types(:founding) + + assert_equal founding, members(:groucho).nested_member_type - members = Member.joins(:nested_member_type).where('member_types.id' => member_types(:founding).id) + members = Member.joins(:nested_member_type).where('member_types.id' => founding.id) assert_equal [members(:groucho)], members - members = Member.includes(:nested_member_type) - assert_equal member_types(:founding), members.first.nested_member_type + assert_queries(4) do + members = Member.includes(:nested_member_type).to_a + end + + 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 + general = categories(:general) + + assert_equal general, members(:groucho).club_category members = Member.joins(:club_category).where('categories.id' => categories(:technology).id) assert_equal [members(:blarpy_winkup)], members - # TODO: Make this work - # members = Member.includes(:club_category) - # assert_equal categories(:general), members.first.club_category + assert_queries(4) do + members = Member.includes(:club_category).to_a + end + + 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 -- cgit v1.2.3 From 1e2525bfe0248d873d6d6026f45102853a1c95cd Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Fri, 15 Oct 2010 16:21:42 +0100 Subject: Add assertions for nested through associations loaded by includes with conditions (uses the single-query strategy). Currently one failure to fix. --- .../nested_has_many_through_associations_test.rb | 156 ++++++++++----------- 1 file changed, 75 insertions(+), 81 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 32b03bf076..4d5152ed5d 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -58,18 +58,16 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal [general, general], authors(:david).tags - # Only David has a Post tagged with General - authors = Author.joins(:tags).where('tags.id' => tags(:general).id) - assert_equal [authors(:david)], authors.uniq + 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? - assert_queries(5) do - authors = Author.includes(:tags).to_a - end - + authors = assert_queries(5) { Author.includes(:tags).to_a } assert_no_queries do assert_equal [general, general], authors.first.tags end @@ -85,13 +83,12 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal [luke, david, david], author.subscribers # All authors with subscribers where one of the subscribers' nick is 'alterself' - authors = Author.joins(:subscribers).where('subscribers.nick' => 'alterself') - assert_equal [authors(:david)], authors - - assert_queries(4) do - authors = Author.includes(:subscribers).to_a - end + 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 @@ -107,13 +104,12 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal [founding], members(:groucho).nested_member_types - members = Member.joins(:nested_member_types).where('member_types.id' => founding.id) - assert_equal [members(:groucho)], members - - assert_queries(4) do - members = Member.includes(:nested_member_types).to_a - end + 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 @@ -127,13 +123,12 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal [mustache], members(:groucho).nested_sponsors - members = Member.joins(:nested_sponsors).where('sponsors.id' => mustache.id) - assert_equal [members(:groucho)], members - - assert_queries(4) do - members = Member.includes(:nested_sponsors).to_a - end + 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 @@ -147,18 +142,16 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal [groucho_details, other_details], members(:groucho).organization_member_details - members = Member.joins(:organization_member_details). - where('member_details.id' => member_details(:groucho).id) - assert_equal [members(:groucho), members(:some_other_guy)], members + assert_includes_and_joins_equal( + Member.where('member_details.id' => member_details(:groucho).id), + [members(:groucho), members(:some_other_guy)], :organization_member_details + ) members = Member.joins(:organization_member_details). where('member_details.id' => 9) assert members.empty? - assert_queries(4) do - members = Member.includes(:organization_member_details).to_a - end - + members = assert_queries(4) { Member.includes(:organization_member_details).to_a } assert_no_queries do assert_equal [groucho_details, other_details], members.first.organization_member_details end @@ -172,18 +165,16 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal [groucho_details, other_details], members(:groucho).organization_member_details_2 - members = Member.joins(:organization_member_details_2). - where('member_details.id' => groucho_details.id) - assert_equal [members(:groucho), members(:some_other_guy)], members + assert_includes_and_joins_equal( + Member.where('member_details.id' => groucho_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? - assert_queries(4) do - members = Member.includes(:organization_member_details_2).to_a - end - + members = assert_queries(4) { Member.includes(:organization_member_details_2).to_a } assert_no_queries do assert_equal [groucho_details, other_details], members.first.organization_member_details_2 end @@ -197,13 +188,12 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal [general, cooking], authors(:bob).post_categories - authors = Author.joins(:post_categories).where('categories.id' => cooking.id) - assert_equal [authors(:bob)], authors - - assert_queries(3) do - authors = Author.includes(:post_categories).to_a - end + 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 } assert_no_queries do assert_equal [general, cooking], authors[2].post_categories end @@ -217,13 +207,12 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal [greetings, more], categories(:technology).post_comments - categories = Category.joins(:post_comments).where('comments.id' => more.id) - assert_equal [categories(:general), categories(:technology)], categories - - assert_queries(3) do - categories = Category.includes(:post_comments).to_a - end + assert_includes_and_joins_equal( + Category.where('comments.id' => more.id), + [categories(:general), categories(:technology)], :post_comments + ) + categories = assert_queries(3) { Category.includes(:post_comments).to_a } assert_no_queries do assert_equal [greetings, more], categories[1].post_comments end @@ -237,13 +226,12 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal [greetings, more], authors(:bob).category_post_comments - authors = Author.joins(:category_post_comments).where('comments.id' => comments(:does_it_hurt).id) - assert_equal [authors(:david), authors(:mary)], authors - - assert_queries(5) do - authors = Author.includes(:category_post_comments).to_a - end + assert_includes_and_joins_equal( + Author.where('comments.id' => comments(:does_it_hurt).id), + [authors(:david), authors(:mary)], :category_post_comments + ) + authors = assert_queries(5) { Author.includes(:category_post_comments).to_a } assert_no_queries do assert_equal [greetings, more], authors[2].category_post_comments end @@ -257,13 +245,12 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal [general, general], authors(:david).tagging_tags - authors = Author.joins(:tagging_tags).where('tags.id' => tags(:general).id) - assert_equal [authors(:david)], authors.uniq - - assert_queries(5) do - authors = Author.includes(:tagging_tags).to_a - end + 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 @@ -277,13 +264,12 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal [welcome_general, thinking_general], categorizations(:david_welcome_general).post_taggings - categorizations = Categorization.joins(:post_taggings).where('taggings.id' => welcome_general.id) - assert_equal [categorizations(:david_welcome_general)], categorizations - - assert_queries(4) do - categorizations = Categorization.includes(:post_taggings).to_a - end + assert_includes_and_joins_equal( + Categorization.where('taggings.id' => welcome_general.id), + [categorizations(:david_welcome_general)], :post_taggings + ) + categorizations = assert_queries(4) { Categorization.includes(:post_taggings).to_a } assert_no_queries do assert_equal [welcome_general, thinking_general], categorizations.first.post_taggings end @@ -297,13 +283,12 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal founding, members(:groucho).nested_member_type - members = Member.joins(:nested_member_type).where('member_types.id' => founding.id) - assert_equal [members(:groucho)], members - - assert_queries(4) do - members = Member.includes(:nested_member_type).to_a - end + 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 } assert_no_queries do assert_equal founding, members.first.nested_member_type end @@ -317,13 +302,12 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal general, members(:groucho).club_category - members = Member.joins(:club_category).where('categories.id' => categories(:technology).id) - assert_equal [members(:blarpy_winkup)], members - - assert_queries(4) do - members = Member.includes(:club_category).to_a - end + 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 } assert_no_queries do assert_equal general, members.first.club_category end @@ -379,4 +363,14 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert !scope.where("comments.type" => "SpecialComment").empty? assert !scope.where("comments.type" => "SubSpecialComment").empty? 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 -- cgit v1.2.3 From edc176d33be9499f4c096779c5b4711b5daf0c06 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Fri, 15 Oct 2010 17:46:09 +0100 Subject: Make sure nested through associations are read only --- .../nested_has_many_through_associations_test.rb | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 4d5152ed5d..03ec4281d8 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -363,6 +363,48 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase 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 private -- cgit v1.2.3 From 9ec07348749675110843c44f680da79223218db2 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 19 Oct 2010 00:27:40 +0100 Subject: Properly support conditions on any of the reflections involved in a nested through association --- .../associations/cascaded_eager_loading_test.rb | 6 ++-- activerecord/test/cases/associations/eager_test.rb | 4 +-- .../nested_has_many_through_associations_test.rb | 40 ++++++++++++++++++++-- activerecord/test/cases/batches_test.rb | 2 +- activerecord/test/cases/finder_test.rb | 6 ++-- activerecord/test/cases/relations_test.rb | 18 +++++----- activerecord/test/fixtures/posts.yml | 14 ++++++++ activerecord/test/fixtures/taggings.yml | 28 +++++++++++++++ activerecord/test/fixtures/tags.yml | 4 +++ activerecord/test/models/author.rb | 7 +++- activerecord/test/models/post.rb | 5 +++ activerecord/test/models/tagging.rb | 3 +- activerecord/test/schema/schema.rb | 1 + 13 files changed, 116 insertions(+), 22 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb index 0e9c8a2639..5b24d49a7d 100644 --- a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb +++ b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb @@ -15,7 +15,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase authors = Author.find(:all, :include=>{:posts=>:comments}, :order=>"authors.id") assert_equal 3, authors.size assert_equal 5, authors[0].posts.size - assert_equal 2, 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 @@ -23,7 +23,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase authors = Author.find(:all, :include=>[{:posts=>:comments}, :categorizations], :order=>"authors.id") assert_equal 3, authors.size assert_equal 5, authors[0].posts.size - assert_equal 2, 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 @@ -56,7 +56,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase authors = Author.find(:all, :include=>{:posts=>[:comments, :categorizations]}, :order=>"authors.id") assert_equal 3, authors.size assert_equal 5, authors[0].posts.size - assert_equal 2, 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 diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 2ff0714e9f..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") - [:misc_by_mary, :misc_by_bob, :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/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 03ec4281d8..c39ec5d139 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -92,8 +92,6 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase assert_no_queries do assert_equal [luke, david, david], authors.first.subscribers.sort_by(&:nick) end - - # TODO: Add eager loading test using LEFT OUTER JOIN end # has_many through @@ -325,7 +323,7 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase 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)], author.similar_posts.sort_by(&:id) + 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) @@ -406,6 +404,42 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase 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 } + 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 } + assert_no_queries do + assert_equal [blue], authors[2].misc_post_first_blue_tags_2 + end + end + private def assert_includes_and_joins_equal(query, expected, association) diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb index 70883ad30f..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(5) 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 0476fc94df..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],[2,9],[3,8]], 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/relations_test.rb b/activerecord/test/cases/relations_test.rb index df4e84ca29..0d88c8eded 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -501,22 +501,22 @@ class RelationTest < ActiveRecord::TestCase def test_count posts = Post.scoped - assert_equal 9, posts.count - assert_equal 9, posts.count(:all) - assert_equal 9, 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 7, 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 9, 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 9, posts.select(:comments_count).count(:distinct => false) + assert_equal 11, posts.select(:comments_count).count(:distinct => false) end def test_count_explicit_columns @@ -526,7 +526,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 9, 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') @@ -541,12 +541,12 @@ class RelationTest < ActiveRecord::TestCase def test_size posts = Post.scoped - assert_queries(1) { assert_equal 9, 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 7, best_posts.size } + assert_no_queries { assert_equal 9, best_posts.size } end def test_count_complex_chained_relations diff --git a/activerecord/test/fixtures/posts.yml b/activerecord/test/fixtures/posts.yml index ca6d4c2fe1..264ca164f0 100644 --- a/activerecord/test/fixtures/posts.yml +++ b/activerecord/test/fixtures/posts.yml @@ -64,3 +64,17 @@ misc_by_mary: title: misc post by mary body: hello type: Post + +other_by_bob: + id: 10 + author_id: 3 + title: other post by bob + body: hello + type: Post + +other_by_mary: + id: 11 + author_id: 2 + title: other post by mary + body: hello + type: Post diff --git a/activerecord/test/fixtures/taggings.yml b/activerecord/test/fixtures/taggings.yml index 7cc7198ded..a337cce019 100644 --- a/activerecord/test/fixtures/taggings.yml +++ b/activerecord/test/fixtures/taggings.yml @@ -38,3 +38,31 @@ misc_post_by_mary: tag_id: 2 taggable_id: 9 taggable_type: Post + +misc_by_bob_blue_first: + id: 8 + tag_id: 3 + taggable_id: 8 + taggable_type: Post + comment: first + +misc_by_bob_blue_second: + id: 9 + tag_id: 3 + taggable_id: 8 + taggable_type: Post + comment: second + +other_by_bob_blue: + id: 10 + tag_id: 3 + taggable_id: 10 + taggable_type: Post + comment: first + +other_by_mary_blue: + id: 11 + tag_id: 3 + taggable_id: 11 + taggable_type: Post + comment: first diff --git a/activerecord/test/fixtures/tags.yml b/activerecord/test/fixtures/tags.yml index 6cb886dc46..d4b7c9a4d5 100644 --- a/activerecord/test/fixtures/tags.yml +++ b/activerecord/test/fixtures/tags.yml @@ -5,3 +5,7 @@ general: misc: id: 2 name: Misc + +blue: + id: 3 + name: Blue diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index b5f702018a..c0e082836d 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -86,7 +86,7 @@ class Author < ActiveRecord::Base has_many :tagging, :through => :posts has_many :taggings, :through => :posts has_many :tags, :through => :posts - has_many :similar_posts, :through => :tags, :source => :tagged_posts + has_many :similar_posts, :through => :tags, :source => :tagged_posts, :uniq => true has_many :distinct_tags, :through => :posts, :source => :tags, :select => "DISTINCT tags.*", :order => "tags.name" has_many :post_categories, :through => :posts, :source => :categories has_many :tagging_tags, :through => :taggings, :source => :tag @@ -103,6 +103,11 @@ class Author < ActiveRecord::Base has_many :post_categories, :through => :posts, :source => :categories has_many :category_post_comments, :through => :categories, :source => :post_comments + + has_many :misc_posts, :class_name => 'Post', :conditions => "posts.title LIKE 'misc post%'" + has_many :misc_post_first_blue_tags, :through => :misc_posts, :source => :first_blue_tags + + has_many :misc_post_first_blue_tags_2, :through => :posts, :source => :first_blue_tags_2, :conditions => "posts.title LIKE 'misc post%'" scope :relation_include_posts, includes(:posts) scope :relation_include_tags, includes(:tags) diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index f3b78c3647..281586b438 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -64,6 +64,11 @@ class Post < ActiveRecord::Base has_many :funky_tags, :through => :taggings, :source => :tag has_many :super_tags, :through => :taggings has_one :tagging, :as => :taggable + + has_many :first_taggings, :as => :taggable, :class_name => 'Tagging', :conditions => "taggings.comment = 'first'" + has_many :first_blue_tags, :through => :first_taggings, :source => :tag, :conditions => "tags.name = 'Blue'" + + has_many :first_blue_tags_2, :through => :taggings, :source => :blue_tag, :conditions => "taggings.comment = 'first'" has_many :invalid_taggings, :as => :taggable, :class_name => "Tagging", :conditions => 'taggings.id < 0' has_many :invalid_tags, :through => :invalid_taggings, :source => :tag diff --git a/activerecord/test/models/tagging.rb b/activerecord/test/models/tagging.rb index a1fa1a9750..c92df88e71 100644 --- a/activerecord/test/models/tagging.rb +++ b/activerecord/test/models/tagging.rb @@ -6,5 +6,6 @@ class Tagging < ActiveRecord::Base belongs_to :tag, :include => :tagging belongs_to :super_tag, :class_name => 'Tag', :foreign_key => 'super_tag_id' belongs_to :invalid_tag, :class_name => 'Tag', :foreign_key => 'tag_id' + belongs_to :blue_tag, :class_name => 'Tag', :foreign_key => :tag_id, :conditions => "tags.name = 'Blue'" belongs_to :taggable, :polymorphic => true, :counter_cache => true -end \ No newline at end of file +end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 8b9c56b895..ee129162a6 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -537,6 +537,7 @@ ActiveRecord::Schema.define do t.column :super_tag_id, :integer t.column :taggable_type, :string t.column :taggable_id, :integer + t.string :comment end create_table :tags, :force => true do |t| -- cgit v1.2.3 From 596cc3b2329a9cc4a30c95c157ce36b2d08975df Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 19 Oct 2010 12:47:19 +0100 Subject: Respect the :primary_key option on the through_reflection of (non-nested) through associations --- .../has_many_through_associations_test.rb | 19 ++++++++++++++++++- .../has_one_through_associations_test.rb | 20 +++++++++++++++++++- activerecord/test/fixtures/essays.yml | 6 ++++++ activerecord/test/models/author.rb | 12 +++++++++++- activerecord/test/models/essay.rb | 1 + activerecord/test/schema/schema.rb | 2 ++ 6 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 activerecord/test/fixtures/essays.yml (limited to 'activerecord/test') 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..5a2e6b26aa 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,14 @@ require 'models/developer' require 'models/subscriber' require 'models/book' require 'models/subscription' +require 'models/essay' +require 'models/category' 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 # Dummies to force column loads so query counts are clean. def setup @@ -449,4 +452,18 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase comment = post.comments.build assert author.comments.include?(comment) end + + def test_has_many_through_polymorphic_with_primary_key_option_on_through_reflection + 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 + end + + def test_has_many_through_with_primary_key_option_on_through_reflection + 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..8805968869 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,13 @@ require 'models/member_detail' require 'models/minivan' require 'models/dashboard' require 'models/speedometer' +require 'models/category' +require 'models/author' +require 'models/essay' 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 def setup @member = members(:groucho) @@ -212,4 +216,18 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase minivan.dashboard end end + + def test_has_one_through_polymorphic_with_primary_key_option_on_through_reflection + 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 + end + + def test_has_one_through_with_primary_key_option_on_through_reflection + 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/fixtures/essays.yml b/activerecord/test/fixtures/essays.yml new file mode 100644 index 0000000000..8c96a469e6 --- /dev/null +++ b/activerecord/test/fixtures/essays.yml @@ -0,0 +1,6 @@ +david_modest_proposal: + name: A Modest Proposal + writer_type: Author + writer_id: David + category_id: 1 + author_id: David diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index c0e082836d..1ba01d6b6b 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -95,8 +95,18 @@ class Author < ActiveRecord::Base has_many :subscriptions, :through => :books has_many :subscribers, :through => :subscriptions, :order => "subscribers.nick" # through has_many :through (on through reflection) has_many :distinct_subscribers, :through => :subscriptions, :source => :subscriber, :select => "DISTINCT subscribers.*", :order => "subscribers.nick" - + has_one :essay, :primary_key => :name, :as => :writer + has_one :essay_category, :through => :essay, :source => :category + + has_one :essay_2, :primary_key => :name, :class_name => 'Essay', :foreign_key => :author_id + has_one :essay_category_2, :through => :essay_2, :source => :category + + has_many :essays, :primary_key => :name, :as => :writer + has_many :essay_categories, :through => :essays, :source => :category + + has_many :essays_2, :primary_key => :name, :class_name => 'Essay', :foreign_key => :author_id + has_many :essay_categories_2, :through => :essays_2, :source => :category belongs_to :author_address, :dependent => :destroy belongs_to :author_address_extra, :dependent => :delete, :class_name => "AuthorAddress" diff --git a/activerecord/test/models/essay.rb b/activerecord/test/models/essay.rb index 6c28f5e49b..6a62042863 100644 --- a/activerecord/test/models/essay.rb +++ b/activerecord/test/models/essay.rb @@ -1,3 +1,4 @@ class Essay < ActiveRecord::Base belongs_to :writer, :primary_key => :name, :polymorphic => true + belongs_to :category end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index ee129162a6..b5bf9a7349 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -214,6 +214,8 @@ ActiveRecord::Schema.define do t.string :name t.string :writer_id t.string :writer_type + t.integer :category_id + t.integer :author_id end create_table :events, :force => true do |t| -- cgit v1.2.3 From 01838636c6136d9a649ace71db61bb7990f9bd82 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 19 Oct 2010 14:14:06 +0100 Subject: Support for :primary_key option on the source reflection of a through association, where the source is a has_one or has_many --- .../cases/associations/has_many_through_associations_test.rb | 12 +++++++++--- .../cases/associations/has_one_through_associations_test.rb | 12 +++++++++--- activerecord/test/fixtures/essays.yml | 2 +- activerecord/test/fixtures/owners.yml | 1 + activerecord/test/models/author.rb | 2 ++ activerecord/test/models/essay.rb | 3 ++- activerecord/test/schema/schema.rb | 5 +++-- 7 files changed, 27 insertions(+), 10 deletions(-) (limited to 'activerecord/test') 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 5a2e6b26aa..713c492f5e 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -19,12 +19,13 @@ 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, - :essays, :categories + :essays, :categories, :owners # Dummies to force column loads so query counts are clean. def setup @@ -453,14 +454,19 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase assert author.comments.include?(comment) end - def test_has_many_through_polymorphic_with_primary_key_option_on_through_reflection + 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_on_through_reflection + 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) 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 8805968869..39e14b4bfd 100644 --- a/activerecord/test/cases/associations/has_one_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_through_associations_test.rb @@ -12,10 +12,11 @@ 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, :categories, :authors, :essays + :dashboards, :speedometers, :categories, :authors, :essays, :owners def setup @member = members(:groucho) @@ -217,14 +218,19 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase end end - def test_has_one_through_polymorphic_with_primary_key_option_on_through_reflection + 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_on_through_reflection + 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) diff --git a/activerecord/test/fixtures/essays.yml b/activerecord/test/fixtures/essays.yml index 8c96a469e6..9d15d82359 100644 --- a/activerecord/test/fixtures/essays.yml +++ b/activerecord/test/fixtures/essays.yml @@ -2,5 +2,5 @@ david_modest_proposal: name: A Modest Proposal writer_type: Author writer_id: David - category_id: 1 + category_id: General author_id: David diff --git a/activerecord/test/fixtures/owners.yml b/activerecord/test/fixtures/owners.yml index d5493a84b7..2d21ce433c 100644 --- a/activerecord/test/fixtures/owners.yml +++ b/activerecord/test/fixtures/owners.yml @@ -1,6 +1,7 @@ blackbeard: owner_id: 1 name: blackbeard + essay_id: A Modest Proposal ashley: owner_id: 2 diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index 1ba01d6b6b..53b3b80950 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -98,12 +98,14 @@ class Author < ActiveRecord::Base has_one :essay, :primary_key => :name, :as => :writer has_one :essay_category, :through => :essay, :source => :category + has_one :essay_owner, :through => :essay, :source => :owner has_one :essay_2, :primary_key => :name, :class_name => 'Essay', :foreign_key => :author_id has_one :essay_category_2, :through => :essay_2, :source => :category has_many :essays, :primary_key => :name, :as => :writer has_many :essay_categories, :through => :essays, :source => :category + has_many :essay_owners, :through => :essays, :source => :owner has_many :essays_2, :primary_key => :name, :class_name => 'Essay', :foreign_key => :author_id has_many :essay_categories_2, :through => :essays_2, :source => :category diff --git a/activerecord/test/models/essay.rb b/activerecord/test/models/essay.rb index 6a62042863..ec4b982b5b 100644 --- a/activerecord/test/models/essay.rb +++ b/activerecord/test/models/essay.rb @@ -1,4 +1,5 @@ class Essay < ActiveRecord::Base belongs_to :writer, :primary_key => :name, :polymorphic => true - belongs_to :category + belongs_to :category, :primary_key => :name + has_one :owner, :primary_key => :name end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index b5bf9a7349..de3baaf4ab 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -214,8 +214,8 @@ ActiveRecord::Schema.define do t.string :name t.string :writer_id t.string :writer_type - t.integer :category_id - t.integer :author_id + t.string :category_id + t.string :author_id end create_table :events, :force => true do |t| @@ -369,6 +369,7 @@ ActiveRecord::Schema.define do t.string :name t.column :updated_at, :datetime t.column :happy_at, :datetime + t.string :essay_id end -- cgit v1.2.3 From 915ea5ea826d48107e4c1953c7a32cf26727d10e Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 19 Oct 2010 16:13:06 +0100 Subject: Support the :primary_key option on a through reflection in a nested through association --- .../nested_has_many_through_associations_test.rb | 17 ++++++++++++++++- activerecord/test/fixtures/authors.yml | 2 ++ activerecord/test/models/author.rb | 3 +++ activerecord/test/models/organization.rb | 8 +++++++- activerecord/test/schema/schema.rb | 2 ++ 5 files changed, 30 insertions(+), 2 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index c39ec5d139..3a4601b032 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -21,6 +21,7 @@ require 'models/organization' require 'models/category' require 'models/categorization' require 'models/membership' +require 'models/essay' # NOTE: Some of these tests might not really test "nested" HMT associations, as opposed to ones which # are just one level deep. But it's all the same thing really, as the "nested" code is being @@ -31,7 +32,7 @@ class NestedHasManyThroughAssociationsTest < 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 + :categorizations, :memberships, :essays # Through associations can either use the has_many or has_one macros. # @@ -440,6 +441,20 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase 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) diff --git a/activerecord/test/fixtures/authors.yml b/activerecord/test/fixtures/authors.yml index 6f13ec4dac..832236a486 100644 --- a/activerecord/test/fixtures/authors.yml +++ b/activerecord/test/fixtures/authors.yml @@ -3,6 +3,8 @@ david: name: David author_address_id: 1 author_address_extra_id: 2 + organization_id: No Such Agency + owned_essay_id: A Modest Proposal mary: id: 2 diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index 53b3b80950..dd8a20ce9b 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -110,6 +110,9 @@ class Author < ActiveRecord::Base has_many :essays_2, :primary_key => :name, :class_name => 'Essay', :foreign_key => :author_id has_many :essay_categories_2, :through => :essays_2, :source => :category + belongs_to :owned_essay, :primary_key => :name, :class_name => 'Essay' + has_one :owned_essay_category, :through => :owned_essay, :source => :category + belongs_to :author_address, :dependent => :destroy belongs_to :author_address_extra, :dependent => :delete, :class_name => "AuthorAddress" diff --git a/activerecord/test/models/organization.rb b/activerecord/test/models/organization.rb index 1da342a0bd..c18c28c696 100644 --- a/activerecord/test/models/organization.rb +++ b/activerecord/test/models/organization.rb @@ -2,5 +2,11 @@ class Organization < ActiveRecord::Base has_many :member_details has_many :members, :through => :member_details + has_many :authors, :primary_key => :name + has_many :author_essay_categories, :through => :authors, :source => :essay_categories + + has_one :author, :primary_key => :name + has_one :author_owned_essay_category, :through => :author, :source => :owned_essay_category + scope :clubs, { :from => 'clubs' } -end \ No newline at end of file +end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index de3baaf4ab..c77651a782 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -44,6 +44,8 @@ ActiveRecord::Schema.define do t.string :name, :null => false t.integer :author_address_id t.integer :author_address_extra_id + t.string :organization_id + t.string :owned_essay_id end create_table :author_addresses, :force => true do |t| -- cgit v1.2.3 From 1f7415ab3a5b433ecfb0c10d66343a894d73914a Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 19 Oct 2010 16:26:35 +0100 Subject: Fix broken test --- activerecord/test/cases/json_serialization_test.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/json_serialization_test.rb b/activerecord/test/cases/json_serialization_test.rb index 430be003ac..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 -- cgit v1.2.3 From 82b889f7d37249adaa606558d4c05356b3e84d9a Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 19 Oct 2010 17:22:42 +0100 Subject: Add explicit tests for the nested through association changes in reflection.rb --- activerecord/test/cases/reflection_test.rb | 64 ++++++++++++++++++++++++++++++ activerecord/test/models/author.rb | 1 + activerecord/test/models/post.rb | 1 + activerecord/test/models/tagging.rb | 1 + 4 files changed, 67 insertions(+) (limited to 'activerecord/test') 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/models/author.rb b/activerecord/test/models/author.rb index dd8a20ce9b..7dcfbd268b 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -90,6 +90,7 @@ class Author < ActiveRecord::Base has_many :distinct_tags, :through => :posts, :source => :tags, :select => "DISTINCT tags.*", :order => "tags.name" has_many :post_categories, :through => :posts, :source => :categories has_many :tagging_tags, :through => :taggings, :source => :tag + has_many :tags_with_primary_key, :through => :posts has_many :books has_many :subscriptions, :through => :books diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index 281586b438..7c919a55eb 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -63,6 +63,7 @@ class Post < ActiveRecord::Base has_many :misc_tags, :through => :taggings, :source => :tag, :conditions => "tags.name = 'Misc'" has_many :funky_tags, :through => :taggings, :source => :tag has_many :super_tags, :through => :taggings + has_many :tags_with_primary_key, :through => :taggings, :source => :tag_with_primary_key has_one :tagging, :as => :taggable has_many :first_taggings, :as => :taggable, :class_name => 'Tagging', :conditions => "taggings.comment = 'first'" diff --git a/activerecord/test/models/tagging.rb b/activerecord/test/models/tagging.rb index c92df88e71..c6ff8d390b 100644 --- a/activerecord/test/models/tagging.rb +++ b/activerecord/test/models/tagging.rb @@ -7,5 +7,6 @@ class Tagging < ActiveRecord::Base belongs_to :super_tag, :class_name => 'Tag', :foreign_key => 'super_tag_id' belongs_to :invalid_tag, :class_name => 'Tag', :foreign_key => 'tag_id' belongs_to :blue_tag, :class_name => 'Tag', :foreign_key => :tag_id, :conditions => "tags.name = 'Blue'" + belongs_to :tag_with_primary_key, :class_name => 'Tag', :foreign_key => :tag_id, :primary_key => :custom_primary_key belongs_to :taggable, :polymorphic => true, :counter_cache => true end -- cgit v1.2.3 From 7ee33b80a2048ec3801f02018b0ea81d2abe0011 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 19 Oct 2010 17:29:19 +0100 Subject: Remove various comments and code which were just being used during the development of nested through association support (OMFGZ, I might just have nearly finished this\! --- .../cases/associations/nested_has_many_through_associations_test.rb | 5 ----- 1 file changed, 5 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 3a4601b032..23fa1709ce 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -23,11 +23,6 @@ require 'models/categorization' require 'models/membership' require 'models/essay' -# NOTE: Some of these tests might not really test "nested" HMT associations, as opposed to ones which -# are just one level deep. But it's all the same thing really, as the "nested" code is being -# written in a generic way which applies to "non-nested" HMT associations too. So let's just shove -# all useful tests in here for now and then work out where they ought to live properly later. - class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase fixtures :authors, :books, :posts, :subscriptions, :subscribers, :tags, :taggings, :people, :readers, :references, :jobs, :ratings, :comments, :members, :member_details, -- cgit v1.2.3 From d15de7d97f7080d8d3bc47bef89aa8a922f04c67 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 19 Oct 2010 19:25:44 +0100 Subject: Add explicit ordering to nested_has_many_through_associations_test.rb as this was causing failures under postgres --- .../nested_has_many_through_associations_test.rb | 69 ++++++++++++---------- 1 file changed, 37 insertions(+), 32 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 23fa1709ce..274ecdaba7 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -76,7 +76,7 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase luke, david = subscribers(:first), subscribers(:second) author = authors(:david) - assert_equal [luke, david, david], author.subscribers + 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( @@ -134,10 +134,11 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase 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 + 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), + Member.where('member_details.id' => member_details(:groucho).id).order('member_details.id'), [members(:groucho), members(:some_other_guy)], :organization_member_details ) @@ -145,9 +146,9 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase where('member_details.id' => 9) assert members.empty? - members = assert_queries(4) { Member.includes(:organization_member_details).to_a } + 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 + assert_equal [groucho_details, other_details], members.first.organization_member_details.sort_by(&:id) end end @@ -157,10 +158,11 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase 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 + 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), + Member.where('member_details.id' => groucho_details.id).order('member_details.id'), [members(:groucho), members(:some_other_guy)], :organization_member_details_2 ) @@ -168,9 +170,9 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase where('member_details.id' => 9) assert members.empty? - members = assert_queries(4) { Member.includes(:organization_member_details_2).to_a } + 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 + assert_equal [groucho_details, other_details], members.first.organization_member_details_2.sort_by(&:id) end end @@ -180,16 +182,16 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase 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 + 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 } + 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 + assert_equal [general, cooking], authors[2].post_categories.sort_by(&:id) end end @@ -199,16 +201,16 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase 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 + assert_equal [greetings, more], categories(:technology).post_comments.order('comments.id') assert_includes_and_joins_equal( - Category.where('comments.id' => more.id), + 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 } + 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 + assert_equal [greetings, more], categories[1].post_comments.sort_by(&:id) end end @@ -218,16 +220,16 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase 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 + 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), + 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 } + 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 + assert_equal [greetings, more], authors[2].category_post_comments.sort_by(&:id) end end @@ -256,16 +258,17 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase 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 + 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), + 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 } + 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 + assert_equal [welcome_general, thinking_general], categorizations.first.post_taggings.sort_by(&:id) end end @@ -282,7 +285,7 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase [members(:groucho)], :nested_member_type ) - members = assert_queries(4) { Member.includes(:nested_member_type).to_a } + 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 @@ -301,7 +304,7 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase [members(:blarpy_winkup)], :club_category ) - members = assert_queries(4) { Member.includes(:club_category).to_a } + 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 @@ -314,12 +317,14 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase 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 + 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) + 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) @@ -333,7 +338,7 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase end def test_has_many_through_with_foreign_key_option_on_through_reflection - assert_equal [posts(:welcome), posts(:authorless)], people(:david).agents_posts + 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) @@ -341,7 +346,7 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase end def test_has_many_through_with_foreign_key_option_on_source_reflection - assert_equal [people(:michael), people(:susan)], jobs(:unicyclist).agents + assert_equal [people(:michael), people(:susan)], jobs(:unicyclist).agents.order('people.id') jobs = Job.joins(:agents) assert_equal [jobs(:unicyclist), jobs(:unicyclist)], jobs @@ -413,7 +418,7 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase 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 } + 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 @@ -430,7 +435,7 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase [bob], :misc_post_first_blue_tags_2 ) - authors = assert_queries(4) { Author.includes(:misc_post_first_blue_tags_2).to_a } + 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 -- cgit v1.2.3 From 383d545c88266ef579f225bc8bfb3d3b807ca5bc Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 19 Oct 2010 19:33:25 +0100 Subject: Add explicit ordering in relations_test.rb, as the lack of this was causing failures against postgres --- activerecord/test/cases/relations_test.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 0d88c8eded..0b143224be 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -251,27 +251,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 @@ -279,22 +279,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 -- cgit v1.2.3 From 8e53e058acea471eab7a1609dc150aa9fdbfa833 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 19 Oct 2010 21:41:00 +0100 Subject: Rename nested_has_many_through_associations_test.rb because it does not only concern has_many associations --- .../nested_has_many_through_associations_test.rb | 467 --------------------- .../nested_through_associations_test.rb | 467 +++++++++++++++++++++ 2 files changed, 467 insertions(+), 467 deletions(-) delete mode 100644 activerecord/test/cases/associations/nested_has_many_through_associations_test.rb create mode 100644 activerecord/test/cases/associations/nested_through_associations_test.rb (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb deleted file mode 100644 index 274ecdaba7..0000000000 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ /dev/null @@ -1,467 +0,0 @@ -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 NestedHasManyThroughAssociationsTest < 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/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 -- cgit v1.2.3 From 9a1a32ac2b8a526f543367bc7e8258bbd7e6a164 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sun, 31 Oct 2010 11:21:28 +0000 Subject: Fix naughty trailing whitespace --- .../has_many_through_associations_test.rb | 10 +- .../has_one_through_associations_test.rb | 12 +- .../nested_through_associations_test.rb | 180 ++++++++++----------- activerecord/test/cases/reflection_test.rb | 18 +-- activerecord/test/models/author.rb | 6 +- activerecord/test/models/categorization.rb | 2 +- activerecord/test/models/category.rb | 2 +- activerecord/test/models/job.rb | 2 +- activerecord/test/models/member.rb | 8 +- activerecord/test/models/member_detail.rb | 2 +- activerecord/test/models/organization.rb | 2 +- activerecord/test/models/person.rb | 2 +- activerecord/test/models/post.rb | 4 +- activerecord/test/models/reference.rb | 2 +- 14 files changed, 126 insertions(+), 126 deletions(-) (limited to 'activerecord/test') 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 713c492f5e..4e398751d2 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -456,19 +456,19 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase 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 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 39e14b4bfd..1cf8c0539d 100644 --- a/activerecord/test/cases/associations/has_one_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_through_associations_test.rb @@ -217,22 +217,22 @@ 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 diff --git a/activerecord/test/cases/associations/nested_through_associations_test.rb b/activerecord/test/cases/associations/nested_through_associations_test.rb index bfc290e877..db7c8b6c45 100644 --- a/activerecord/test/cases/associations/nested_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_through_associations_test.rb @@ -30,18 +30,18 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase :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. @@ -51,18 +51,18 @@ 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 - + 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 @@ -74,236 +74,236 @@ 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) - + 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 @@ -320,34 +320,34 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase 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 @@ -355,7 +355,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase 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? @@ -366,101 +366,101 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase 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 diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index a85ba623e1..66fe754046 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -200,7 +200,7 @@ 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), @@ -208,10 +208,10 @@ class ReflectionTest < ActiveRecord::TestCase 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'"], @@ -220,7 +220,7 @@ class ReflectionTest < ActiveRecord::TestCase ] 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%'"], [], @@ -229,27 +229,27 @@ class ReflectionTest < ActiveRecord::TestCase 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 diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index 7dcfbd268b..43bfd93e60 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -96,7 +96,7 @@ class Author < ActiveRecord::Base has_many :subscriptions, :through => :books has_many :subscribers, :through => :subscriptions, :order => "subscribers.nick" # through has_many :through (on through reflection) has_many :distinct_subscribers, :through => :subscriptions, :source => :subscriber, :select => "DISTINCT subscribers.*", :order => "subscribers.nick" - + has_one :essay, :primary_key => :name, :as => :writer has_one :essay_category, :through => :essay, :source => :category has_one :essay_owner, :through => :essay, :source => :owner @@ -107,7 +107,7 @@ class Author < ActiveRecord::Base has_many :essays, :primary_key => :name, :as => :writer has_many :essay_categories, :through => :essays, :source => :category has_many :essay_owners, :through => :essays, :source => :owner - + has_many :essays_2, :primary_key => :name, :class_name => 'Essay', :foreign_key => :author_id has_many :essay_categories_2, :through => :essays_2, :source => :category @@ -119,7 +119,7 @@ class Author < ActiveRecord::Base has_many :post_categories, :through => :posts, :source => :categories has_many :category_post_comments, :through => :categories, :source => :post_comments - + has_many :misc_posts, :class_name => 'Post', :conditions => "posts.title LIKE 'misc post%'" has_many :misc_post_first_blue_tags, :through => :misc_posts, :source => :first_blue_tags diff --git a/activerecord/test/models/categorization.rb b/activerecord/test/models/categorization.rb index bddc1e5f0c..8e2fa96498 100644 --- a/activerecord/test/models/categorization.rb +++ b/activerecord/test/models/categorization.rb @@ -2,6 +2,6 @@ class Categorization < ActiveRecord::Base belongs_to :post belongs_to :category belongs_to :author - + has_many :post_taggings, :through => :author, :source => :taggings end diff --git a/activerecord/test/models/category.rb b/activerecord/test/models/category.rb index c933943813..95825c72ef 100644 --- a/activerecord/test/models/category.rb +++ b/activerecord/test/models/category.rb @@ -23,7 +23,7 @@ class Category < ActiveRecord::Base has_many :categorizations has_many :authors, :through => :categorizations, :select => 'authors.*, categorizations.post_id' - + has_many :post_comments, :through => :posts, :source => :comments end diff --git a/activerecord/test/models/job.rb b/activerecord/test/models/job.rb index 46b1d87aa1..f7b0e787b1 100644 --- a/activerecord/test/models/job.rb +++ b/activerecord/test/models/job.rb @@ -2,6 +2,6 @@ class Job < ActiveRecord::Base has_many :references has_many :people, :through => :references belongs_to :ideal_reference, :class_name => 'Reference' - + has_many :agents, :through => :people end diff --git a/activerecord/test/models/member.rb b/activerecord/test/models/member.rb index bed62f8b7f..fbf0b80164 100644 --- a/activerecord/test/models/member.rb +++ b/activerecord/test/models/member.rb @@ -9,15 +9,15 @@ class Member < ActiveRecord::Base has_one :member_detail has_one :organization, :through => :member_detail belongs_to :member_type - + has_many :nested_member_types, :through => :member_detail, :source => :member_type has_one :nested_member_type, :through => :member_detail, :source => :member_type - + has_many :nested_sponsors, :through => :sponsor_club, :source => :sponsor has_one :nested_sponsor, :through => :sponsor_club, :source => :sponsor - + has_many :organization_member_details, :through => :member_detail has_many :organization_member_details_2, :through => :organization, :source => :member_details - + has_one :club_category, :through => :club, :source => :category end diff --git a/activerecord/test/models/member_detail.rb b/activerecord/test/models/member_detail.rb index 0f53b69ced..fe619f8732 100644 --- a/activerecord/test/models/member_detail.rb +++ b/activerecord/test/models/member_detail.rb @@ -2,6 +2,6 @@ class MemberDetail < ActiveRecord::Base belongs_to :member belongs_to :organization has_one :member_type, :through => :member - + has_many :organization_member_details, :through => :organization, :source => :member_details end diff --git a/activerecord/test/models/organization.rb b/activerecord/test/models/organization.rb index c18c28c696..4a4111833f 100644 --- a/activerecord/test/models/organization.rb +++ b/activerecord/test/models/organization.rb @@ -4,7 +4,7 @@ class Organization < ActiveRecord::Base has_many :authors, :primary_key => :name has_many :author_essay_categories, :through => :authors, :source => :essay_categories - + has_one :author, :primary_key => :name has_one :author_owned_essay_category, :through => :author, :source => :owned_essay_category diff --git a/activerecord/test/models/person.rb b/activerecord/test/models/person.rb index d35c51b660..5a5b6f9626 100644 --- a/activerecord/test/models/person.rb +++ b/activerecord/test/models/person.rb @@ -13,7 +13,7 @@ class Person < ActiveRecord::Base belongs_to :primary_contact, :class_name => 'Person' has_many :agents, :class_name => 'Person', :foreign_key => 'primary_contact_id' belongs_to :number1_fan, :class_name => 'Person' - + has_many :agents_posts, :through => :agents, :source => :posts has_many :agents_posts_authors, :through => :agents_posts, :source => :author diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index 68d2b79a3b..e9c8c02e45 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -46,7 +46,7 @@ class Post < ActiveRecord::Base has_one :very_special_comment_with_post, :class_name => "VerySpecialComment", :include => :post has_many :special_comments has_many :nonexistant_comments, :class_name => 'Comment', :conditions => 'comments.id < 0' - + has_many :special_comments_ratings, :through => :special_comments, :source => :ratings has_and_belongs_to_many :categories @@ -65,7 +65,7 @@ class Post < ActiveRecord::Base has_many :super_tags, :through => :taggings has_many :tags_with_primary_key, :through => :taggings, :source => :tag_with_primary_key has_one :tagging, :as => :taggable - + has_many :first_taggings, :as => :taggable, :class_name => 'Tagging', :conditions => "taggings.comment = 'first'" has_many :first_blue_tags, :through => :first_taggings, :source => :tag, :conditions => "tags.name = 'Blue'" diff --git a/activerecord/test/models/reference.rb b/activerecord/test/models/reference.rb index 2feb15d706..87d4a71963 100644 --- a/activerecord/test/models/reference.rb +++ b/activerecord/test/models/reference.rb @@ -1,7 +1,7 @@ class Reference < ActiveRecord::Base belongs_to :person belongs_to :job - + has_many :agents_posts_authors, :through => :person end -- cgit v1.2.3 From 026dbd28d9dbaddb7cdd7d6fdc1349cc2f43242f Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sun, 31 Oct 2010 11:16:16 +0000 Subject: Fix bug with 0bb85ed9ffa9808926b46e8f7e59cab5b85ac19f which missed out a fixtures declaration in cascaded_eager_loading_test.rb --- activerecord/test/cases/associations/cascaded_eager_loading_test.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb index 81e99036af..d997385266 100644 --- a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb +++ b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb @@ -10,7 +10,8 @@ require 'models/reply' require 'models/person' class CascadedEagerLoadingTest < ActiveRecord::TestCase - fixtures :authors, :mixins, :companies, :posts, :topics, :accounts, :comments, :categorizations, :people + fixtures :authors, :mixins, :companies, :posts, :topics, :accounts, :comments, + :categorizations, :people, :categories def test_eager_association_loading_with_cascaded_two_levels authors = Author.find(:all, :include=>{:posts=>:comments}, :order=>"authors.id") -- cgit v1.2.3 From 083d6f267611472b8acfb9801e64971ee6d19994 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sun, 31 Oct 2010 11:27:58 +0000 Subject: Update new tests in cascaded_eager_loading_test.rb to work with the modified fixtures in this branch --- .../test/cases/associations/cascaded_eager_loading_test.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb index d997385266..dbc3bcf758 100644 --- a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb +++ b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb @@ -51,24 +51,24 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase categories = Category.joins(:categorizations).includes([{:posts=>:comments}, :authors]) assert_nothing_raised do - assert_equal 2, categories.count - assert_equal 2, categories.all.uniq.size # Must uniq since instantiating with inner joins will get dupes + assert_equal 3, categories.count + assert_equal 3, categories.all.uniq.size # Must uniq since instantiating with inner joins will get dupes end end def test_cascaded_eager_association_loading_with_duplicated_includes categories = Category.includes(:categorizations).includes(:categorizations => :author).where("categorizations.id is not null") assert_nothing_raised do - assert_equal 2, categories.count - assert_equal 2, categories.all.size + assert_equal 3, categories.count + assert_equal 3, categories.all.size end end def test_cascaded_eager_association_loading_with_twice_includes_edge_cases categories = Category.includes(:categorizations => :author).includes(:categorizations => :post).where("posts.id is not null") assert_nothing_raised do - assert_equal 2, categories.count - assert_equal 2, categories.all.size + assert_equal 3, categories.count + assert_equal 3, categories.all.size end end -- cgit v1.2.3 From 73c0b390b3a1ea9487c3f667352463a90af6dd71 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Fri, 4 Mar 2011 22:29:40 +0000 Subject: When preloading has_and_belongs_to_many associations, we should only instantiate one AR object per actual record in the database. (Even when IM is off.) --- activerecord/test/cases/associations/eager_test.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index ed6337b596..40c82f2fb8 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -525,6 +525,22 @@ class EagerAssociationTest < ActiveRecord::TestCase assert posts[1].categories.include?(categories(:general)) end + # This is only really relevant when the identity map is off. Since the preloader for habtm + # gets raw row hashes from the database and then instantiates them, this test ensures that + # it only instantiates one actual object per record from the database. + def test_has_and_belongs_to_many_should_not_instantiate_same_records_multiple_times + welcome = posts(:welcome) + categories = Category.includes(:posts) + + general = categories.find { |c| c == categories(:general) } + technology = categories.find { |c| c == categories(:technology) } + + post1 = general.posts.to_a.find { |p| p == posts(:welcome) } + post2 = technology.posts.to_a.find { |p| p == posts(:welcome) } + + assert_equal post1.object_id, post2.object_id + end + def test_eager_with_has_many_and_limit_and_conditions_on_the_eagers posts = authors(:david).posts.find(:all, :include => :comments, -- cgit v1.2.3 From ddf83d14f1c7ddae07a285a8ad7c45f652edc843 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sat, 5 Mar 2011 20:10:24 +0000 Subject: Add a test for STI on the through where the through is nested, and change the code which support this --- .../cases/associations/nested_through_associations_test.rb | 9 +++++++++ activerecord/test/fixtures/taggings.yml | 10 ++++++++++ activerecord/test/models/post.rb | 1 + activerecord/test/models/rating.rb | 1 + 4 files changed, 21 insertions(+) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_through_associations_test.rb b/activerecord/test/cases/associations/nested_through_associations_test.rb index a4ac69782a..0dd407f342 100644 --- a/activerecord/test/cases/associations/nested_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_through_associations_test.rb @@ -425,6 +425,15 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase assert !scope.where("comments.type" => "SubSpecialComment").empty? end + def test_has_many_through_with_sti_on_nested_through_reflection + taggings = posts(:sti_comments).special_comments_ratings_taggings + assert_equal [taggings(:special_comment_rating)], taggings + + scope = Post.joins(:special_comments_ratings_taggings).where(:id => posts(:sti_comments).id) + assert scope.where("comments.type" => "Comment").empty? + assert !scope.where("comments.type" => "SpecialComment").empty? + end + def test_nested_has_many_through_writers_should_raise_error david = authors(:david) subscriber = subscribers(:first) diff --git a/activerecord/test/fixtures/taggings.yml b/activerecord/test/fixtures/taggings.yml index a337cce019..d339c12b25 100644 --- a/activerecord/test/fixtures/taggings.yml +++ b/activerecord/test/fixtures/taggings.yml @@ -66,3 +66,13 @@ other_by_mary_blue: taggable_id: 11 taggable_type: Post comment: first + +special_comment_rating: + id: 12 + taggable_id: 2 + taggable_type: Rating + +normal_comment_rating: + id: 13 + taggable_id: 1 + taggable_type: Rating diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index b39325f949..c3843fd264 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -50,6 +50,7 @@ class Post < ActiveRecord::Base has_many :nonexistant_comments, :class_name => 'Comment', :conditions => 'comments.id < 0' has_many :special_comments_ratings, :through => :special_comments, :source => :ratings + has_many :special_comments_ratings_taggings, :through => :special_comments_ratings, :source => :taggings has_and_belongs_to_many :categories has_and_belongs_to_many :special_categories, :join_table => "categories_posts", :association_foreign_key => 'category_id' diff --git a/activerecord/test/models/rating.rb b/activerecord/test/models/rating.rb index 12c4b5affa..25a52c4ad7 100644 --- a/activerecord/test/models/rating.rb +++ b/activerecord/test/models/rating.rb @@ -1,3 +1,4 @@ class Rating < ActiveRecord::Base belongs_to :comment + has_many :taggings, :as => :taggable end -- cgit v1.2.3 From 7fddb942624478a23173dfa379f7ade6a0fc9218 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sat, 5 Mar 2011 22:07:30 +0000 Subject: Push source_type and polymorphic conditions out of ThroughAssociation and JoinDependency::JoinAssociation and into the reflection instead. --- activerecord/test/cases/reflection_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index 9529ae56b8..baaa08a359 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -216,7 +216,7 @@ class ReflectionTest < ActiveRecord::TestCase def test_through_conditions expected = [ ["tags.name = 'Blue'"], - ["taggings.comment = 'first'"], + ["taggings.comment = 'first'", {"taggable_type"=>"Post"}], ["posts.title LIKE 'misc post%'"] ] actual = Author.reflect_on_association(:misc_post_first_blue_tags).through_conditions @@ -224,7 +224,7 @@ class ReflectionTest < ActiveRecord::TestCase expected = [ ["tags.name = 'Blue'", "taggings.comment = 'first'", "posts.title LIKE 'misc post%'"], - [], + [{"taggable_type"=>"Post"}], [] ] actual = Author.reflect_on_association(:misc_post_first_blue_tags_2).through_conditions -- cgit v1.2.3 From cee3f9b36d01e6d54e0bd4c2fd06bee369bfff12 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 7 Mar 2011 00:04:06 +0000 Subject: Referencing a table via the ON condition in a join should force that table to be eager-loaded via a JOIN rather than via subsequent queries. --- activerecord/test/cases/relations_test.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 54537f11a8..ac586e2a63 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -850,4 +850,19 @@ class RelationTest < ActiveRecord::TestCase def test_primary_key assert_equal "id", Post.scoped.primary_key end + + def test_eager_loading_with_conditions_on_joins + scope = Post.includes(:comments) + + # This references the comments table, and so it should cause the comments to be eager + # loaded via a JOIN, rather than by subsequent queries. + scope = scope.joins( + Post.arel_table.create_join( + Post.arel_table, + Post.arel_table.create_on(Comment.arel_table[:id].eq(3)) + ) + ) + + assert scope.eager_loading? + end end -- cgit v1.2.3 From 2d3d9e3531d0d49a94ded10b993640053bd76c03 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Thu, 10 Mar 2011 19:28:26 +0000 Subject: Rename Reflection#through_reflection_chain and #through_options to Reflection#chain and Reflection#options as they now no longer relate solely to through associations. --- activerecord/test/cases/reflection_test.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index baaa08a359..4b881969cc 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -202,24 +202,24 @@ class ReflectionTest < ActiveRecord::TestCase assert_kind_of ThroughReflection, Subscriber.reflect_on_association(:books) end - def test_through_reflection_chain + def test_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 + actual = Organization.reflect_on_association(:author_essay_categories).chain assert_equal expected, actual end - def test_through_conditions + def test_conditions expected = [ ["tags.name = 'Blue'"], ["taggings.comment = 'first'", {"taggable_type"=>"Post"}], ["posts.title LIKE 'misc post%'"] ] - actual = Author.reflect_on_association(:misc_post_first_blue_tags).through_conditions + actual = Author.reflect_on_association(:misc_post_first_blue_tags).conditions assert_equal expected, actual expected = [ @@ -227,7 +227,7 @@ class ReflectionTest < ActiveRecord::TestCase [{"taggable_type"=>"Post"}], [] ] - actual = Author.reflect_on_association(:misc_post_first_blue_tags_2).through_conditions + actual = Author.reflect_on_association(:misc_post_first_blue_tags_2).conditions assert_equal expected, actual end -- cgit v1.2.3 From 39a6f4f25d958783c73377ac52886c9edc19632e Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Fri, 11 Mar 2011 00:51:57 +0000 Subject: Simplify implementation of ThroughReflection#chain --- activerecord/test/cases/reflection_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index 4b881969cc..918bc0a842 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -204,7 +204,7 @@ class ReflectionTest < ActiveRecord::TestCase def test_chain expected = [ - Author.reflect_on_association(:essay_categories), + Organization.reflect_on_association(:author_essay_categories), Author.reflect_on_association(:essays), Organization.reflect_on_association(:authors) ] -- cgit v1.2.3 From 37d93ea16046add35fecd8c279e868869ee744a5 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sat, 12 Mar 2011 09:32:20 +0000 Subject: Fix tests under postgres - we should always put conditions in the WHERE part not in ON constraints because postgres requires that the table has been joined before the condition references it. --- .../test/cases/associations/nested_through_associations_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/nested_through_associations_test.rb b/activerecord/test/cases/associations/nested_through_associations_test.rb index 0dd407f342..dd450a2a8e 100644 --- a/activerecord/test/cases/associations/nested_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_through_associations_test.rb @@ -272,7 +272,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase 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'), + Author.where('comments.id' => comments(:does_it_hurt).id).order('authors.id'), [authors(:david), authors(:mary)], :category_post_comments ) end -- cgit v1.2.3 From 9abc94c44516afdcfe4a3b202c336c9578fd6d0d Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Wed, 16 Mar 2011 18:54:34 +0000 Subject: oracle, y u defy me --- activerecord/test/cases/associations/join_model_test.rb | 2 +- activerecord/test/cases/reflection_test.rb | 10 +++++----- activerecord/test/models/author.rb | 6 ++++-- activerecord/test/models/post.rb | 8 ++++---- activerecord/test/models/tagging.rb | 2 +- 5 files changed, 15 insertions(+), 13 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index 543eff7d8b..f54d69e7fa 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -305,7 +305,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase 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) + assert_equal [authors(:david), authors(:bob)], posts(:thinking).authors_using_custom_pk.order('authors.id') end def test_both_scoped_and_explicit_joins_should_be_respected diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index 918bc0a842..97d9669483 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -215,16 +215,16 @@ class ReflectionTest < ActiveRecord::TestCase def test_conditions expected = [ - ["tags.name = 'Blue'"], - ["taggings.comment = 'first'", {"taggable_type"=>"Post"}], - ["posts.title LIKE 'misc post%'"] + [{ :tags => { :name => 'Blue' } }], + [{ :taggings => { :comment => 'first' } }, { "taggable_type" => "Post" }], + [{ :posts => { :title => ['misc post by bob', 'misc post by mary'] } }] ] actual = Author.reflect_on_association(:misc_post_first_blue_tags).conditions assert_equal expected, actual expected = [ - ["tags.name = 'Blue'", "taggings.comment = 'first'", "posts.title LIKE 'misc post%'"], - [{"taggable_type"=>"Post"}], + [{ :tags => { :name => 'Blue' } }, { :taggings => { :comment => 'first' } }, { :posts => { :title => ['misc post by bob', 'misc post by mary'] } }], + [{ "taggable_type" => "Post" }], [] ] actual = Author.reflect_on_association(:misc_post_first_blue_tags_2).conditions diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index f362f70dec..e0cbc44265 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -131,10 +131,12 @@ class Author < ActiveRecord::Base has_many :post_categories, :through => :posts, :source => :categories has_many :category_post_comments, :through => :categories, :source => :post_comments - has_many :misc_posts, :class_name => 'Post', :conditions => "posts.title LIKE 'misc post%'" + has_many :misc_posts, :class_name => 'Post', + :conditions => { :posts => { :title => ['misc post by bob', 'misc post by mary'] } } has_many :misc_post_first_blue_tags, :through => :misc_posts, :source => :first_blue_tags - has_many :misc_post_first_blue_tags_2, :through => :posts, :source => :first_blue_tags_2, :conditions => "posts.title LIKE 'misc post%'" + has_many :misc_post_first_blue_tags_2, :through => :posts, :source => :first_blue_tags_2, + :conditions => { :posts => { :title => ['misc post by bob', 'misc post by mary'] } } scope :relation_include_posts, includes(:posts) scope :relation_include_tags, includes(:tags) diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index c3843fd264..82894a3d57 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -73,16 +73,16 @@ class Post < ActiveRecord::Base has_many :tags_with_destroy, :through => :taggings, :source => :tag, :dependent => :destroy has_many :tags_with_nullify, :through => :taggings, :source => :tag, :dependent => :nullify - has_many :misc_tags, :through => :taggings, :source => :tag, :conditions => "tags.name = 'Misc'" + has_many :misc_tags, :through => :taggings, :source => :tag, :conditions => { :tags => { :name => 'Misc' } } has_many :funky_tags, :through => :taggings, :source => :tag has_many :super_tags, :through => :taggings has_many :tags_with_primary_key, :through => :taggings, :source => :tag_with_primary_key has_one :tagging, :as => :taggable - has_many :first_taggings, :as => :taggable, :class_name => 'Tagging', :conditions => "taggings.comment = 'first'" - has_many :first_blue_tags, :through => :first_taggings, :source => :tag, :conditions => "tags.name = 'Blue'" + has_many :first_taggings, :as => :taggable, :class_name => 'Tagging', :conditions => { :taggings => { :comment => 'first' } } + has_many :first_blue_tags, :through => :first_taggings, :source => :tag, :conditions => { :tags => { :name => 'Blue' } } - has_many :first_blue_tags_2, :through => :taggings, :source => :blue_tag, :conditions => "taggings.comment = 'first'" + has_many :first_blue_tags_2, :through => :taggings, :source => :blue_tag, :conditions => { :taggings => { :comment => 'first' } } has_many :invalid_taggings, :as => :taggable, :class_name => "Tagging", :conditions => 'taggings.id < 0' has_many :invalid_tags, :through => :invalid_taggings, :source => :tag diff --git a/activerecord/test/models/tagging.rb b/activerecord/test/models/tagging.rb index 17e627a60e..ef323df158 100644 --- a/activerecord/test/models/tagging.rb +++ b/activerecord/test/models/tagging.rb @@ -6,7 +6,7 @@ class Tagging < ActiveRecord::Base belongs_to :tag, :include => :tagging belongs_to :super_tag, :class_name => 'Tag', :foreign_key => 'super_tag_id' belongs_to :invalid_tag, :class_name => 'Tag', :foreign_key => 'tag_id' - belongs_to :blue_tag, :class_name => 'Tag', :foreign_key => :tag_id, :conditions => "tags.name = 'Blue'" + belongs_to :blue_tag, :class_name => 'Tag', :foreign_key => :tag_id, :conditions => { :tags => { :name => 'Blue' } } belongs_to :tag_with_primary_key, :class_name => 'Tag', :foreign_key => :tag_id, :primary_key => :custom_primary_key belongs_to :interpolated_tag, :class_name => 'Tag', :foreign_key => :tag_id, :conditions => proc { "1 = #{1}" } belongs_to :taggable, :polymorphic => true, :counter_cache => true -- cgit v1.2.3 From 5b84aebd14fdb1aa9746a8404589c9ada4bcbcbb Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Fri, 18 Mar 2011 23:14:45 +0000 Subject: Add order clauses to fix some tests which were failing under 1.8 on oracle and postgres --- activerecord/test/cases/identity_map_test.rb | 18 +++++++++--------- activerecord/test/cases/relations_test.rb | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/identity_map_test.rb b/activerecord/test/cases/identity_map_test.rb index 399d6c26df..89f7b92d09 100644 --- a/activerecord/test/cases/identity_map_test.rb +++ b/activerecord/test/cases/identity_map_test.rb @@ -207,31 +207,31 @@ class IdentityMapTest < 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 # With IM we'll retrieve post object from previous query, it'll have comments # already preloaded from first call assert_queries(1) do - posts = Post.preload(:comments).to_a + posts = Post.preload(:comments).order('posts.id') 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 # With IM we'll retrieve post object from previous query, it'll have comments # already preloaded from first call assert_queries(1) do - posts = Post.preload(:author).to_a + posts = Post.preload(:author).order('posts.id') assert posts.first.author end assert_queries(1) do - posts = Post.preload(:author, :comments).to_a + posts = Post.preload(:author, :comments).order('posts.id') assert posts.first.author assert posts.first.comments.first end @@ -239,22 +239,22 @@ class IdentityMapTest < 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(1) 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(1) do - posts = Post.includes(:author, :comments).to_a + posts = Post.includes(:author, :comments).order('posts.id') assert posts.first.author assert posts.first.comments.first end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 680e1d50cf..94916f61c5 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -286,7 +286,7 @@ class RelationTest < ActiveRecord::TestCase end assert_queries(ActiveRecord::IdentityMap.enabled? ? 1 : 2) do - posts = Post.preload(:comments).to_a + posts = Post.preload(:comments).order('posts.id') assert posts.first.comments.first end @@ -296,12 +296,12 @@ class RelationTest < ActiveRecord::TestCase end assert_queries(ActiveRecord::IdentityMap.enabled? ? 1 : 2) do - posts = Post.preload(:author).to_a + posts = Post.preload(:author).order('posts.id') assert posts.first.author end assert_queries(ActiveRecord::IdentityMap.enabled? ? 1 : 3) do - posts = Post.preload(:author, :comments).to_a + posts = Post.preload(:author, :comments).order('posts.id') assert posts.first.author assert posts.first.comments.first end @@ -314,7 +314,7 @@ class RelationTest < ActiveRecord::TestCase end assert_queries(ActiveRecord::IdentityMap.enabled? ? 1 : 2) do - posts = Post.scoped.includes(:comments) + posts = Post.scoped.includes(:comments).order('posts.id') assert posts.first.comments.first end @@ -324,7 +324,7 @@ class RelationTest < ActiveRecord::TestCase end assert_queries(ActiveRecord::IdentityMap.enabled? ? 1 : 3) do - posts = Post.includes(:author, :comments).to_a + posts = Post.includes(:author, :comments).order('posts.id') assert posts.first.author assert posts.first.comments.first end -- cgit v1.2.3 From ed97c395178391c9083b20121cdd6606a9e92d14 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 22 Mar 2011 10:10:33 -0700 Subject: adding missing require --- activerecord/test/cases/associations/join_model_test.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index f54d69e7fa..1f95b31497 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -2,6 +2,7 @@ require "cases/helper" require 'models/tag' require 'models/tagging' require 'models/post' +require 'models/rating' require 'models/item' require 'models/comment' require 'models/author' -- cgit v1.2.3 From baa237c974fee8023dd704a4efb418ff0e963de0 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 21 Mar 2011 21:36:05 -0300 Subject: Allow to read and write AR attributes with non valid identifiers --- activerecord/test/cases/base_test.rb | 12 ++++++++++++ activerecord/test/schema/schema.rb | 3 +++ 2 files changed, 15 insertions(+) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index d03fc68a11..fba7af741d 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -45,6 +45,8 @@ class ReadonlyTitlePost < Post attr_readonly :title end +class Weird < ActiveRecord::Base; end + class Boolean < ActiveRecord::Base; end class BasicsTest < ActiveRecord::TestCase @@ -477,6 +479,16 @@ class BasicsTest < ActiveRecord::TestCase assert_equal "changed", post.body end + def test_non_valid_identifier_column_name + weird = Weird.create('a$b' => 'value') + weird.reload + assert_equal 'value', weird.send('a$b') + + weird.update_attribute('a$b', 'value2') + weird.reload + assert_equal 'value2', weird.send('a$b') + end + def test_multiparameter_attributes_on_date attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "24" } topic = Topic.find(1) diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index bdadd0698b..362475de36 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -690,6 +690,9 @@ ActiveRecord::Schema.define do t.integer :molecule_id t.string :name end + create_table :weirds, :force => true do |t| + t.string 'a$b' + end except 'SQLite' do # fk_test_has_fk should be before fk_test_has_pk -- cgit v1.2.3 From 8ee81d21fb103be31adb8e0dcde8ed8f5e90a798 Mon Sep 17 00:00:00 2001 From: Murray Steele Date: Fri, 11 Mar 2011 11:41:30 +0000 Subject: Failing test case to show that habtm join table contents are removed when a model is destroyed but the destruction is blocked by a before_destroy. --- .../test/cases/habtm_destroy_order_test.rb | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/habtm_destroy_order_test.rb b/activerecord/test/cases/habtm_destroy_order_test.rb index 15598392e2..f2b91d977e 100644 --- a/activerecord/test/cases/habtm_destroy_order_test.rb +++ b/activerecord/test/cases/habtm_destroy_order_test.rb @@ -13,5 +13,39 @@ class HabtmDestroyOrderTest < ActiveRecord::TestCase sicp.destroy end end + assert !sicp.destroyed? + end + + test "not destroying a student with lessons leaves student<=>lesson association intact" do + # test a normal before_destroy doesn't destroy the habtm joins + begin + sicp = Lesson.new(:name => "SICP") + ben = Student.new(:name => "Ben Bitdiddle") + # add a before destroy to student + Student.class_eval do + before_destroy do + raise ActiveRecord::Rollback unless lessons.empty? + end + end + ben.lessons << sicp + ben.save! + ben.destroy + assert !ben.reload.lessons.empty? + ensure + # get rid of it so Student is still like it was + Student.reset_callbacks(:destroy) + end + end + + test "not destroying a lesson with students leaves student<=>lesson association intact" do + # test a more aggressive before_destroy doesn't destroy the habtm joins and still throws the exception + sicp = Lesson.new(:name => "SICP") + ben = Student.new(:name => "Ben Bitdiddle") + sicp.students << ben + sicp.save! + assert_raises LessonError do + sicp.destroy + end + assert !sicp.reload.students.empty? end end -- cgit v1.2.3 From c5908a86492271ca55a6f54ccfd62b521cdc47c9 Mon Sep 17 00:00:00 2001 From: Adam Meehan Date: Tue, 1 Mar 2011 22:18:46 +1100 Subject: Fix before_type_cast for timezone aware attributes by caching converted value on write. Also remove read method reload arg on timezone attributes. --- activerecord/test/cases/attribute_methods_test.rb | 26 ++++++++++------------- 1 file changed, 11 insertions(+), 15 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index dfacf58da8..d8638ee776 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -118,22 +118,18 @@ class AttributeMethodsTest < ActiveRecord::TestCase end def test_read_attributes_before_type_cast_on_datetime - developer = Developer.find(:first) - if current_adapter?(:Mysql2Adapter, :OracleAdapter) - # Mysql2 and Oracle adapters keep the value in Time instance - assert_equal developer.created_at.to_s(:db), developer.attributes_before_type_cast["created_at"].to_s(:db) - else - assert_equal developer.created_at.to_s(:db), developer.attributes_before_type_cast["created_at"].to_s + in_time_zone "Pacific Time (US & Canada)" do + record = @target.new + + record.written_on = "345643456" + assert_equal "345643456", record.written_on_before_type_cast + assert_equal nil, record.written_on + + record.written_on = "2009-10-11 12:13:14" + assert_equal "2009-10-11 12:13:14", record.written_on_before_type_cast + assert_equal Time.zone.parse("2009-10-11 12:13:14"), record.written_on + assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone end - - developer.created_at = "345643456" - - assert_equal developer.created_at_before_type_cast, "345643456" - assert_equal developer.created_at, nil - - developer.created_at = "2010-03-21 21:23:32" - assert_equal developer.created_at_before_type_cast, "2010-03-21 21:23:32" - assert_equal developer.created_at, Time.parse("2010-03-21 21:23:32") end def test_hash_content -- cgit v1.2.3