diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index dc61ab3c31..bd06810c36 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,13 @@ *SVN* +* Added support for eagerly including polymorphic has_one associations. (closes #4525) [Rick] + + class Post < ActiveRecord::Base + has_one :tagging, :as => :taggable + end + + Post.find :all, :include => :tagging + * Added descriptive error messages for invalid has_many :through associations: going through :has_one or :has_and_belongs_to_many [Rick] * Added support for going through a polymorphic has_many association: (closes #4401) [Rick] diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 5319fa39e8..7b6257ec03 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1392,7 +1392,7 @@ module ActiveRecord @aliased_prefix = "t#{ join_dependency.joins.size }" @aliased_table_name = table_name # start with the table name @parent_table_name = parent.active_record.table_name - + if !parent.table_joins.blank? && parent.table_joins.to_s.downcase =~ %r{join(\s+\w+)?\s+#{aliased_table_name.downcase}\son} join_dependency.table_aliases[aliased_table_name] += 1 end @@ -1473,12 +1473,16 @@ module ActiveRecord aliased_table_name, "#{reflection.options[:as]}_type", klass.quote(parent.active_record.base_class.name) ] - + when reflection.macro == :has_one && reflection.options[:as] + " LEFT OUTER JOIN %s ON %s.%s = %s.%s AND %s.%s = %s " % [ + table_name_and_alias, + aliased_table_name, "#{reflection.options[:as]}_id", + parent.aliased_table_name, parent.primary_key, + aliased_table_name, "#{reflection.options[:as]}_type", + klass.quote(reflection.active_record.name) + ] else - foreign_key = options[:foreign_key] || case reflection.macro - when :has_many then reflection.active_record.to_s.classify - when :has_one then reflection.active_record.to_s - end.foreign_key + foreign_key = options[:foreign_key] || reflection.active_record.name.foreign_key " LEFT OUTER JOIN %s ON %s.%s = %s.%s " % [ table_name_and_alias, aliased_table_name, foreign_key, diff --git a/activerecord/test/associations_join_model_test.rb b/activerecord/test/associations_join_model_test.rb index b7f0af173b..4a11d4c5eb 100644 --- a/activerecord/test/associations_join_model_test.rb +++ b/activerecord/test/associations_join_model_test.rb @@ -208,6 +208,14 @@ class AssociationsJoinModelTest < Test::Unit::TestCase end end + def test_include_polymorphic_has_one + post = Post.find_by_id(posts(:welcome).id, :include => :tagging) + tagging = taggings(:welcome_general) + assert_no_queries do + assert_equal tagging, post.tagging + end + end + def test_include_polymorphic_has_many_through posts = Post.find(:all, :order => 'posts.id') posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id') @@ -303,6 +311,14 @@ class AssociationsJoinModelTest < Test::Unit::TestCase assert_equal [taggings(:welcome_general), taggings(:thinking_general)], authors(:david).taggings.uniq.sort_by { |t| t.id } end + def test_has_many_through_polymorphic_has_many_with_eager_loading + author = Author.find_by_id(authors(:david).id, :include => :taggings) + expected_taggings = [taggings(:welcome_general), taggings(:thinking_general)] + assert_no_queries do + assert_equal expected_taggings, author.taggings.uniq.sort_by { |t| t.id } + end + end + def test_has_many_through_has_many_through assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).tags } end diff --git a/activerecord/test/fixtures/tag.rb b/activerecord/test/fixtures/tag.rb index ed3c6ce34a..c12ec0c188 100644 --- a/activerecord/test/fixtures/tag.rb +++ b/activerecord/test/fixtures/tag.rb @@ -1,5 +1,5 @@ class Tag < ActiveRecord::Base - has_many :taggings, :as => :taggable + has_many :taggings has_many :taggables, :through => :taggings - has_one :tagging, :as => :taggable + has_one :tagging end \ No newline at end of file