From ea09bf5419ec752dd020d26b03533afa457d09d6 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Tue, 18 Jul 2017 04:15:45 +0900 Subject: [PATCH] Fix `JoinDependency` with using a custom table Without this fix, `JoinDependency` doesn't use a custom table alias: ``` % ARCONN=sqlite3 be ruby -w -Itest test/cases/relations_test.rb -n test_using_a_custom_table_with_joins_affects_the_wheres Using sqlite3 Run options: -n test_using_a_custom_table_with_joins_affects_the_wheres --seed 14531 E Error:RelationTest#test_using_a_custom_table_with_joins_affects_the_wheres: ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: posts.author_id: SELECT "omg_posts".* FROM "posts" "omg_posts" INNER JOIN "authors" ON "authors"."id" = "posts"."author_id" WHERE "omg_posts"."title" = ? LIMIT ? ``` --- .../associations/join_dependency.rb | 4 ++-- .../associations/join_dependency/join_base.rb | 11 +++++---- .../active_record/relation/finder_methods.rb | 2 +- .../lib/active_record/relation/merger.rb | 7 +++--- .../active_record/relation/query_methods.rb | 4 +--- activerecord/test/cases/relations_test.rb | 23 +++++++++++++------ 6 files changed, 31 insertions(+), 20 deletions(-) diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb index 5c8ecf42b4..4a3fb6eaec 100644 --- a/activerecord/lib/active_record/associations/join_dependency.rb +++ b/activerecord/lib/active_record/associations/join_dependency.rb @@ -88,11 +88,11 @@ module ActiveRecord # associations # => [:appointments] # joins # => [] # - def initialize(base, associations, joins, eager_loading: true) + def initialize(base, table, associations, joins, eager_loading: true) @alias_tracker = AliasTracker.create_with_joins(base.connection, base.table_name, joins) @eager_loading = eager_loading tree = self.class.make_tree associations - @join_root = JoinBase.new base, build(tree, base) + @join_root = JoinBase.new(base, table, build(tree, base)) @join_root.children.each { |child| construct_tables! @join_root, child } end diff --git a/activerecord/lib/active_record/associations/join_dependency/join_base.rb b/activerecord/lib/active_record/associations/join_dependency/join_base.rb index f5f22ebfca..d4e26d5397 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_base.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_base.rb @@ -4,14 +4,17 @@ module ActiveRecord module Associations class JoinDependency # :nodoc: class JoinBase < JoinPart # :nodoc: + attr_reader :table + + def initialize(base_klass, table, children) + super(base_klass, children) + @table = table + end + def match?(other) return true if self == other super && base_klass == other.base_klass end - - def table - base_klass.arel_table - end end end end diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 7121dcade8..57b7d3c2e9 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -397,7 +397,7 @@ module ActiveRecord def construct_join_dependency(joins = [], eager_loading: true) including = eager_load_values + includes_values - ActiveRecord::Associations::JoinDependency.new(@klass, including, joins, eager_loading: eager_loading) + ActiveRecord::Associations::JoinDependency.new(klass, table, including, joins, eager_loading: eager_loading) end def construct_relation_for_association_calculations diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb index 5dac00724a..6251f6fc33 100644 --- a/activerecord/lib/active_record/relation/merger.rb +++ b/activerecord/lib/active_record/relation/merger.rb @@ -119,9 +119,10 @@ module ActiveRecord end end - join_dependency = ActiveRecord::Associations::JoinDependency.new(other.klass, - joins_dependency, - []) + join_dependency = ActiveRecord::Associations::JoinDependency.new( + other.klass, other.table, joins_dependency, [] + ) + relation.joins! rest @relation = relation.joins join_dependency diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index c26c176c7b..efb55391e7 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -1020,9 +1020,7 @@ module ActiveRecord join_list = join_nodes + convert_join_strings_to_ast(manager, string_joins) join_dependency = ActiveRecord::Associations::JoinDependency.new( - @klass, - association_joins, - join_list + klass, table, association_joins, join_list ) join_infos = join_dependency.join_constraints stashed_association_joins, join_type diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 82e1077e87..316ea75e36 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -1785,15 +1785,15 @@ class RelationTest < ActiveRecord::TestCase end test "using a custom table affects the wheres" do - table_alias = Post.arel_table.alias("omg_posts") - - table_metadata = ActiveRecord::TableMetadata.new(Post, table_alias) - predicate_builder = ActiveRecord::PredicateBuilder.new(table_metadata) - relation = ActiveRecord::Relation.create(Post, table_alias, predicate_builder) - post = posts(:welcome) - assert_equal post, relation.where!(title: post.title).take + assert_equal post, custom_post_relation.where!(title: post.title).take + end + + test "using a custom table with joins affects the joins" do + post = posts(:welcome) + + assert_equal post, custom_post_relation.joins(:author).where!(title: post.title).take end test "#load" do @@ -1950,4 +1950,13 @@ class RelationTest < ActiveRecord::TestCase end end end + + private + def custom_post_relation + table_alias = Post.arel_table.alias("omg_posts") + table_metadata = ActiveRecord::TableMetadata.new(Post, table_alias) + predicate_builder = ActiveRecord::PredicateBuilder.new(table_metadata) + + ActiveRecord::Relation.create(Post, table_alias, predicate_builder) + end end