mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Implicit through table joins should be appeared before user supplied joins
#36293 was an issue for through association with `joins` for a long time, but since #35864 through association with `left_joins` would also be affected by the issue. Implicit through table joins should be appeared before user supplied joins, otherwise loading through association with joins will cause a statement invalid error. Fixes #36293. ``` % ARCONN=postgresql bundle exec ruby -w -Itest test/cases/associations/has_many_through_associations_test .rb -n test_through_association_with_joins Using postgresql Run options: -n test_through_association_with_joins --seed 7116 # Running: E Error: HasManyThroughAssociationsTest#test_through_association_with_joins: ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "posts" LINE 1: ... "comments_posts" ON "comments_posts"."post_id" = "posts"."i... ^ : SELECT "comments".* FROM "comments" INNER JOIN "comments" "comments_posts" ON "comments_posts"."post_id" = "posts"."id" INNER JOIN "posts" ON "comments"."post_id" = "posts"."id" WHERE "posts"."author_id" = $1 rails test test/cases/associations/has_many_through_associations_test.rb:61 Finished in 0.388657s, 2.5730 runs/s, 0.0000 assertions/s. 1 runs, 0 assertions, 0 failures, 1 errors, 0 skips ```
This commit is contained in:
parent
339be65d66
commit
7412b7f8a6
2 changed files with 19 additions and 17 deletions
|
@ -1128,27 +1128,21 @@ module ActiveRecord
|
|||
|
||||
association_joins = buckets[:association_join]
|
||||
stashed_joins = buckets[:stashed_join]
|
||||
join_nodes = buckets[:join_node].uniq
|
||||
string_joins = buckets[:string_join].map(&:strip).uniq
|
||||
join_nodes = buckets[:join_node].tap(&:uniq!)
|
||||
string_joins = buckets[:string_join].delete_if(&:blank?).map!(&:strip).tap(&:uniq!)
|
||||
|
||||
join_list = join_nodes + convert_join_strings_to_ast(string_joins)
|
||||
alias_tracker = alias_tracker(join_list, aliases)
|
||||
string_joins.map! { |join| table.create_string_join(Arel.sql(join)) }
|
||||
|
||||
join_dependency = construct_join_dependency(association_joins, join_type)
|
||||
join_sources = manager.join_sources
|
||||
join_sources.concat(join_nodes) unless join_nodes.empty?
|
||||
|
||||
joins = join_dependency.join_constraints(stashed_joins, alias_tracker)
|
||||
joins.each { |join| manager.from(join) }
|
||||
unless association_joins.empty? && stashed_joins.empty?
|
||||
alias_tracker = alias_tracker(join_nodes + string_joins, aliases)
|
||||
join_dependency = construct_join_dependency(association_joins, join_type)
|
||||
join_sources.concat(join_dependency.join_constraints(stashed_joins, alias_tracker))
|
||||
end
|
||||
|
||||
manager.join_sources.concat(join_list)
|
||||
|
||||
alias_tracker.aliases
|
||||
end
|
||||
|
||||
def convert_join_strings_to_ast(joins)
|
||||
joins
|
||||
.flatten
|
||||
.reject(&:blank?)
|
||||
.map { |join| table.create_string_join(Arel.sql(join)) }
|
||||
join_sources.concat(string_joins) unless string_joins.empty?
|
||||
end
|
||||
|
||||
def build_select(arel)
|
||||
|
|
|
@ -58,6 +58,14 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
|
|||
assert_equal preloaded, Marshal.load(Marshal.dump(preloaded))
|
||||
end
|
||||
|
||||
def test_through_association_with_joins
|
||||
assert_equal [comments(:eager_other_comment1)], authors(:mary).comments.merge(Post.joins(:comments))
|
||||
end
|
||||
|
||||
def test_through_association_with_left_joins
|
||||
assert_equal [comments(:eager_other_comment1)], authors(:mary).comments.merge(Post.left_joins(:comments))
|
||||
end
|
||||
|
||||
def test_preload_with_nested_association
|
||||
posts = Post.preload(:author, :author_favorites_with_scope).to_a
|
||||
|
||||
|
|
Loading…
Reference in a new issue