diff --git a/activerecord/lib/active_record/associations/through_association_scope.rb b/activerecord/lib/active_record/associations/through_association_scope.rb index acddfda924e90d21b1b9989d6f1795d3f79e2b2f..48386ee1243d2336dc6410a56381dd7e201dd1cc 100644 --- a/activerecord/lib/active_record/associations/through_association_scope.rb +++ b/activerecord/lib/active_record/associations/through_association_scope.rb @@ -55,33 +55,35 @@ def construct_select(custom_select = nil) end def construct_joins(custom_joins = nil) - polymorphic_join = nil + right = @reflection.through_reflection.klass.arel_table + left = @reflection.klass.arel_table + + conditions = [] + if @reflection.source_reflection.macro == :belongs_to reflection_primary_key = @reflection.klass.primary_key source_primary_key = @reflection.source_reflection.primary_key_name if @reflection.options[:source_type] - polymorphic_join = "AND %s.%s = %s" % [ - @reflection.through_reflection.quoted_table_name, "#{@reflection.source_reflection.options[:foreign_type]}", - @owner.class.quote_value(@reflection.options[:source_type]) - ] + column = @reflection.source_reflection.options[:foreign_type] + conditions << + right[column].eq(@reflection.options[:source_type]) end else reflection_primary_key = @reflection.source_reflection.primary_key_name source_primary_key = @reflection.through_reflection.klass.primary_key if @reflection.source_reflection.options[:as] - polymorphic_join = "AND %s.%s = %s" % [ - @reflection.quoted_table_name, "#{@reflection.source_reflection.options[:as]}_type", - @owner.class.quote_value(@reflection.through_reflection.klass.name) - ] + column = "#{@reflection.source_reflection.options[:as]}_type" + conditions << + left[column].eq(@reflection.through_reflection.klass.name) end end - "INNER JOIN %s ON %s.%s = %s.%s %s #{@reflection.options[:joins]} #{custom_joins}" % [ - @reflection.through_reflection.quoted_table_name, - @reflection.quoted_table_name, reflection_primary_key, - @reflection.through_reflection.quoted_table_name, source_primary_key, - polymorphic_join - ] + conditions << + left[reflection_primary_key].eq(right[source_primary_key]) + + right.create_join( + right, + right.create_on(right.create_and(conditions))) end # Construct attributes for associate pointing to owner. diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index ef14f48a8f4de72fc24e55d2a69abddc75d49ae4..8e50f4a9bc0f37b02a5b7808f22a92d38ba2a591 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -247,6 +247,8 @@ def build_joins(manager, joins) 'association_join' when ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation 'stashed_join' + when Arel::Nodes::Join + 'join_node' else raise 'unknown class: %s' % join.class.name end @@ -254,12 +256,22 @@ def build_joins(manager, joins) association_joins = buckets['association_join'] || [] stashed_association_joins = buckets['stashed_join'] || [] + join_nodes = buckets['join_node'] || [] string_joins = (buckets['string_join'] || []).map { |x| x.strip }.uniq + join_list = custom_join_ast(manager, string_joins) - join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, association_joins, join_list) + join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new( + @klass, + association_joins, + join_list + ) + + join_nodes.each do |join| + join_dependency.table_aliases[join.left.name.downcase] = 1 + end join_dependency.graft(*stashed_association_joins) @@ -270,9 +282,9 @@ def build_joins(manager, joins) association.join_to(manager) end - return manager unless join_list + manager.join_sources.concat join_nodes + manager.join_sources.concat join_list - join_list.each { |j| manager.from j } manager end