From e6f953fc395e3ff2fdea1ff60743f83f73158e7b Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Fri, 2 Aug 2019 03:35:44 +0900
Subject: Deduplicate joins values

#36805 have one possible regression that failing deduplication if
`joins_values` have complex order (e.g. `joins_values = [join_node_a,
:comments, :tags, join_node_a]`).

This fixes the deduplication to take it in the first phase before
grouping.
---
 activerecord/lib/active_record/relation/query_methods.rb       |  6 +++---
 .../test/cases/associations/inner_join_association_test.rb     | 10 ++++++++++
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 29e2e2cedc..2876bae302 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -1114,7 +1114,7 @@ module ActiveRecord
           else
             join
           end
-        end.compact_blank!
+        end.compact_blank!.uniq!
 
         while joins.first.is_a?(Arel::Nodes::Join)
           join_node = joins.shift
@@ -1144,8 +1144,8 @@ module ActiveRecord
       def build_join_query(manager, buckets, join_type, aliases)
         association_joins = buckets[:association_join]
         stashed_joins     = buckets[:stashed_join]
-        leading_joins     = buckets[:leading_join].tap(&:uniq!)
-        join_nodes        = buckets[:join_node].tap(&:uniq!)
+        leading_joins     = buckets[:leading_join]
+        join_nodes        = buckets[:join_node]
 
         join_sources = manager.join_sources
         join_sources.concat(leading_joins) unless leading_joins.empty?
diff --git a/activerecord/test/cases/associations/inner_join_association_test.rb b/activerecord/test/cases/associations/inner_join_association_test.rb
index b65af4b819..166a59ec7b 100644
--- a/activerecord/test/cases/associations/inner_join_association_test.rb
+++ b/activerecord/test/cases/associations/inner_join_association_test.rb
@@ -69,6 +69,16 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase
     assert_equal [expected], Person.joins(string_join).joins(agents.create_join(agents, agents.create_on(constraint)))
   end
 
+  def test_deduplicate_joins
+    posts = Post.arel_table
+    constraint = posts[:author_id].eq(Author.arel_attribute(:id))
+
+    authors = Author.joins(posts.create_join(posts, posts.create_on(constraint)))
+    authors = authors.joins(:author_address).merge(authors.where("posts.type": "SpecialPost"))
+
+    assert_equal [authors(:david)], authors
+  end
+
   def test_construct_finder_sql_ignores_empty_joins_hash
     sql = Author.joins({}).to_sql
     assert_no_match(/JOIN/i, sql)
-- 
cgit v1.2.3