mirror of
https://github.com/github/rails.git
synced 2026-01-10 07:07:54 -05:00
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).
This commit is contained in:
@@ -22,9 +22,8 @@ module ActiveRecord
|
||||
# Build SQL conditions from attributes, qualified by table name.
|
||||
def construct_conditions
|
||||
reflection = @reflection.through_reflection_chain.last
|
||||
table_name = reflection.quoted_table_name
|
||||
conditions = construct_quoted_owner_attributes(reflection).map do |attr, value|
|
||||
"#{table_name}.#{attr} = #{value}"
|
||||
"#{table_aliases[reflection]}.#{attr} = #{value}"
|
||||
end
|
||||
conditions << sql_conditions if sql_conditions
|
||||
"(" + conditions.join(') AND (') + ")"
|
||||
@@ -67,21 +66,23 @@ module ActiveRecord
|
||||
polymorphic_join = nil
|
||||
|
||||
case
|
||||
when left.options[:as]
|
||||
when left.source_reflection.nil?
|
||||
left_primary_key = left.primary_key_name
|
||||
right_primary_key = right.klass.primary_key
|
||||
|
||||
polymorphic_join = "AND %s.%s = %s" % [
|
||||
left.quoted_table_name, "#{left.options[:as]}_type",
|
||||
@owner.class.quote_value(right.klass.name)
|
||||
]
|
||||
if left.options[:as]
|
||||
polymorphic_join = "AND %s.%s = %s" % [
|
||||
table_aliases[left], "#{left.options[:as]}_type",
|
||||
@owner.class.quote_value(right.klass.name)
|
||||
]
|
||||
end
|
||||
when left.source_reflection.macro == :belongs_to
|
||||
left_primary_key = left.klass.primary_key
|
||||
right_primary_key = left.source_reflection.primary_key_name
|
||||
|
||||
if left.options[:source_type]
|
||||
polymorphic_join = "AND %s.%s = %s" % [
|
||||
right.quoted_table_name,
|
||||
table_aliases[right],
|
||||
left.source_reflection.options[:foreign_type].to_s,
|
||||
@owner.class.quote_value(left.options[:source_type])
|
||||
]
|
||||
@@ -92,22 +93,45 @@ module ActiveRecord
|
||||
|
||||
if left.source_reflection.options[:as]
|
||||
polymorphic_join = "AND %s.%s = %s" % [
|
||||
left.quoted_table_name,
|
||||
table_aliases[left],
|
||||
"#{left.source_reflection.options[:as]}_type",
|
||||
@owner.class.quote_value(right.klass.name)
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
if right.quoted_table_name == table_aliases[right]
|
||||
table = right.quoted_table_name
|
||||
else
|
||||
table = "#{right.quoted_table_name} #{table_aliases[right]}"
|
||||
end
|
||||
|
||||
joins << "INNER JOIN %s ON %s.%s = %s.%s %s" % [
|
||||
right.quoted_table_name,
|
||||
left.quoted_table_name, left_primary_key,
|
||||
right.quoted_table_name, right_primary_key,
|
||||
table,
|
||||
table_aliases[left], left_primary_key,
|
||||
table_aliases[right], right_primary_key,
|
||||
polymorphic_join
|
||||
]
|
||||
end
|
||||
|
||||
joins
|
||||
joins.join(" ")
|
||||
end
|
||||
|
||||
def table_aliases
|
||||
@table_aliases ||= begin
|
||||
tally = {}
|
||||
@reflection.through_reflection_chain.inject({}) do |aliases, reflection|
|
||||
if tally[reflection.table_name].nil?
|
||||
tally[reflection.table_name] = 1
|
||||
aliases[reflection] = reflection.quoted_table_name
|
||||
else
|
||||
tally[reflection.table_name] += 1
|
||||
aliased_table_name = reflection.table_name + "_#{tally[reflection.table_name]}"
|
||||
aliases[reflection] = reflection.klass.connection.quote_table_name(aliased_table_name)
|
||||
end
|
||||
aliases
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Construct attributes for associate pointing to owner.
|
||||
|
||||
@@ -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
|
||||
|
||||
4
activerecord/test/fixtures/authors.yml
vendored
4
activerecord/test/fixtures/authors.yml
vendored
@@ -7,3 +7,7 @@ david:
|
||||
mary:
|
||||
id: 2
|
||||
name: Mary
|
||||
|
||||
bob:
|
||||
id: 3
|
||||
name: Bob
|
||||
|
||||
14
activerecord/test/fixtures/posts.yml
vendored
14
activerecord/test/fixtures/posts.yml
vendored
@@ -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
|
||||
|
||||
12
activerecord/test/fixtures/taggings.yml
vendored
12
activerecord/test/fixtures/taggings.yml
vendored
@@ -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
|
||||
|
||||
2
activerecord/test/fixtures/tags.yml
vendored
2
activerecord/test/fixtures/tags.yml
vendored
@@ -4,4 +4,4 @@ general:
|
||||
|
||||
misc:
|
||||
id: 2
|
||||
name: Misc
|
||||
name: Misc
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user