diff options
-rw-r--r-- | activerecord/lib/active_record/reflection.rb | 15 | ||||
-rw-r--r-- | activerecord/test/cases/reflection_test.rb | 64 | ||||
-rw-r--r-- | activerecord/test/models/author.rb | 1 | ||||
-rw-r--r-- | activerecord/test/models/post.rb | 1 | ||||
-rw-r--r-- | activerecord/test/models/tagging.rb | 1 |
5 files changed, 80 insertions, 2 deletions
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 7ce2bbb8ae..3448cc506c 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -450,15 +450,26 @@ module ActiveRecord end end + # A through association is nested iff there would be more than one join table def nested? - through_reflection_chain.length > 2 + through_reflection_chain.length > 2 || + through_reflection.macro == :has_and_belongs_to_many end # We want to use the klass from this reflection, rather than just delegate straight to # the source_reflection, because the source_reflection may be polymorphic. We still # need to respect the source_reflection's :primary_key option, though. def association_primary_key - @association_primary_key ||= source_reflection.options[:primary_key] || klass.primary_key + @association_primary_key ||= begin + # Get the "actual" source reflection if the immediate source reflection has a + # source reflection itself + source_reflection = self.source_reflection + while source_reflection.source_reflection + source_reflection = source_reflection.source_reflection + end + + source_reflection.options[:primary_key] || klass.primary_key + end end # Gets an array of possible <tt>:through</tt> source reflection names: 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 |