1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Child joins should be aliased when merging relations

Rails 5.2 does not alias child joins, causing an error about duplicated table/fields:

Example:

Using some code like:
`Post.joins(:author, :categorizations).merge(Author.select(:id)).merge(Categorization.joins(:author))`

*Before this fix:*
`
SELECT ... FROM "posts" INNER JOIN "authors" ON ... INNER JOIN "authors" ON ...
`

*After this fix:*
`
SELECT ... FROM "posts" INNER JOIN "authors" ON ... INNER JOIN "authors" "authors_categorizations" ON ...
`

Before 5.2, Rails aliased the joins, but wrongfully transformed them into a LEFT OUTER JOIN.
This fix will keep them as INNER JOINS, but make sure child joins are aliased, to avoid errors.
This commit is contained in:
Chalo Fernandez 2018-06-06 02:41:13 -05:00
parent d0d3e96492
commit fd689d9fb1
2 changed files with 27 additions and 2 deletions

View file

@ -88,7 +88,7 @@ module ActiveRecord
walk join_root, oj.join_root
else
oj.join_root.children.flat_map { |child|
make_join_constraints(oj.join_root, child, join_type)
make_join_constraints(oj.join_root, child, join_type, true)
}
end
}

View file

@ -5,10 +5,11 @@ require "models/post"
require "models/comment"
require "models/author"
require "models/rating"
require "models/categorization"
module ActiveRecord
class RelationTest < ActiveRecord::TestCase
fixtures :posts, :comments, :authors, :author_addresses, :ratings
fixtures :posts, :comments, :authors, :author_addresses, :ratings, :categorizations
def test_construction
relation = Relation.new(FakeKlass, table: :b)
@ -223,6 +224,30 @@ module ActiveRecord
assert_equal manual_comments_on_post_that_have_author.size, merged_authors_with_commented_posts_relation.to_a.size
end
def test_relation_merging_with_merged_symbol_joins_is_aliased
categorizations_with_authors = Categorization.joins(:author)
queries = capture_sql { Post.joins(:author, :categorizations).merge(Author.select(:id)).merge(categorizations_with_authors).to_a }
nb_inner_join = queries.sum { |sql| sql.scan(/INNER\s+JOIN/i).size }
assert_equal 3, nb_inner_join, "Wrong amount of INNER JOIN in query"
# using `\W` as the column separator
assert queries.any? { |sql| %r[INNER\s+JOIN\s+#{Author.quoted_table_name}\s+\Wauthors_categorizations\W]i.match?(sql) }, "Should be aliasing the child INNER JOINs in query"
end
def test_relation_with_merged_joins_aliased_works
categorizations_with_authors = Categorization.joins(:author)
posts_with_joins_and_merges = Post.joins(:author, :categorizations)
.merge(Author.select(:id)).merge(categorizations_with_authors)
author_with_posts = Author.joins(:posts).ids
categorizations_with_author = Categorization.joins(:author).ids
posts_with_author_and_categorizations = Post.joins(:categorizations).where(author_id: author_with_posts, categorizations: { id: categorizations_with_author }).ids
assert_equal posts_with_author_and_categorizations.size, posts_with_joins_and_merges.count
assert_equal posts_with_author_and_categorizations.size, posts_with_joins_and_merges.to_a.size
end
def test_relation_merging_with_joins_as_join_dependency_pick_proper_parent
post = Post.create!(title: "haha", body: "huhu")
comment = post.comments.create!(body: "hu")