aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Leighton <j@jonathanleighton.com>2010-10-19 17:22:42 +0100
committerJon Leighton <j@jonathanleighton.com>2010-10-19 17:22:42 +0100
commit82b889f7d37249adaa606558d4c05356b3e84d9a (patch)
tree5ef73ccfadb32c90f66890aceb72a1ea80c50d4b
parent1f7415ab3a5b433ecfb0c10d66343a894d73914a (diff)
downloadrails-82b889f7d37249adaa606558d4c05356b3e84d9a.tar.gz
rails-82b889f7d37249adaa606558d4c05356b3e84d9a.tar.bz2
rails-82b889f7d37249adaa606558d4c05356b3e84d9a.zip
Add explicit tests for the nested through association changes in reflection.rb
-rw-r--r--activerecord/lib/active_record/reflection.rb15
-rw-r--r--activerecord/test/cases/reflection_test.rb64
-rw-r--r--activerecord/test/models/author.rb1
-rw-r--r--activerecord/test/models/post.rb1
-rw-r--r--activerecord/test/models/tagging.rb1
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