From 4aa76ed38a8609ad713e2b39ccb1fa97c5c64682 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Sun, 30 Apr 2017 01:00:59 +0900 Subject: Remove unused `association_key` and `table` methods in `Preloader::Association` These are no longer used since b98668decb9712f26118de57623fd15d7d28646d. --- .../lib/active_record/associations/preloader/association.rb | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb index 63ef3f2d8c..4513dce15e 100644 --- a/activerecord/lib/active_record/associations/preloader/association.rb +++ b/activerecord/lib/active_record/associations/preloader/association.rb @@ -31,21 +31,11 @@ module ActiveRecord scope.where(association_key_name => ids) end - def table - klass.arel_table - end - # The name of the key on the associated records def association_key_name raise NotImplementedError end - # This is overridden by HABTM as the condition should be on the foreign_key column in - # the join table - def association_key - klass.arel_attribute(association_key_name, table) - end - # The name of the key on the model which declares the association def owner_key_name raise NotImplementedError -- cgit v1.2.3 From 2bfa2c02a891d4817832807343c6f1d56e9bae50 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Thu, 18 May 2017 10:42:26 +0900 Subject: Fix preloading association with scope including joins --- .../lib/active_record/associations/preloader.rb | 3 -- .../associations/preloader/association.rb | 58 ++++++---------------- .../associations/preloader/through_association.rb | 13 +++-- 3 files changed, 25 insertions(+), 49 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb index 208d1b2670..a18994cec4 100644 --- a/activerecord/lib/active_record/associations/preloader.rb +++ b/activerecord/lib/active_record/associations/preloader.rb @@ -54,8 +54,6 @@ module ActiveRecord autoload :BelongsTo, "active_record/associations/preloader/belongs_to" end - NULL_RELATION = Struct.new(:values, :where_clause, :joins_values).new({}, Relation::WhereClause.empty, []) - # Eager loads the named associations for the given Active Record record(s). # # In this description, 'association name' shall refer to the name passed @@ -93,7 +91,6 @@ module ActiveRecord def preload(records, associations, preload_scope = nil) records = Array.wrap(records).compact.uniq associations = Array.wrap(associations) - preload_scope = preload_scope || NULL_RELATION if records.empty? [] diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb index 4513dce15e..85343040db 100644 --- a/activerecord/lib/active_record/associations/preloader/association.rb +++ b/activerecord/lib/active_record/associations/preloader/association.rb @@ -11,7 +11,6 @@ module ActiveRecord @reflection = reflection @preload_scope = preload_scope @model = owners.first && owners.first.class - @scope = nil @preloaded_records = [] end @@ -23,14 +22,6 @@ module ActiveRecord raise NotImplementedError end - def scope - @scope ||= build_scope - end - - def records_for(ids) - scope.where(association_key_name => ids) - end - # The name of the key on the associated records def association_key_name raise NotImplementedError @@ -104,54 +95,35 @@ module ActiveRecord # Make several smaller queries if necessary or make one query if the adapter supports it slices = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size) @preloaded_records = slices.flat_map do |slice| - records_for(slice).load(&block) + records_for(slice, &block) end @preloaded_records.group_by do |record| convert_key(record[association_key_name]) end end + def records_for(ids, &block) + scope.where(association_key_name => ids).load(&block) + end + + def scope + @scope ||= build_scope + end + def reflection_scope @reflection_scope ||= reflection.scope_for(klass) end def build_scope - scope = klass.unscoped - - values = reflection_scope.values - preload_values = preload_scope.values - - scope.where_clause = reflection_scope.where_clause + preload_scope.where_clause - scope.references_values = Array(values[:references]) + Array(preload_values[:references]) - - if preload_values[:select] || values[:select] - scope._select!(preload_values[:select] || values[:select]) - end - scope.includes! preload_values[:includes] || values[:includes] - if preload_scope.joins_values.any? - scope.joins!(preload_scope.joins_values) - else - scope.joins!(reflection_scope.joins_values) - end - - if order_values = preload_values[:order] || values[:order] - scope.order!(order_values) - end - - if preload_values[:reordering] || values[:reordering] - scope.reordering_value = true - end - - if preload_values[:readonly] || values[:readonly] - scope.readonly! - end + scope = klass.default_scoped - if options[:as] - scope.where!(klass.table_name => { reflection.type => model.base_class.sti_name }) + if reflection.type + scope.where!(reflection.type => model.base_class.sti_name) end - scope.unscope_values = Array(values[:unscope]) + Array(preload_values[:unscope]) - klass.default_scoped.merge(scope) + scope.merge!(reflection_scope) + scope.merge!(preload_scope) if preload_scope + scope end end end diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb index 34587fd3f5..0999746cd5 100644 --- a/activerecord/lib/active_record/associations/preloader/through_association.rb +++ b/activerecord/lib/active_record/associations/preloader/through_association.rb @@ -79,17 +79,24 @@ module ActiveRecord def through_scope scope = through_reflection.klass.unscoped + values = reflection_scope.values if options[:source_type] scope.where! reflection.foreign_type => options[:source_type] else unless reflection_scope.where_clause.empty? - scope.includes_values = Array(reflection_scope.values[:includes] || options[:source]) + scope.includes_values = Array(values[:includes] || options[:source]) scope.where_clause = reflection_scope.where_clause + if joins = values[:joins] + scope.joins!(source_reflection.name => joins) + end + if left_outer_joins = values[:left_outer_joins] + scope.left_outer_joins!(source_reflection.name => left_outer_joins) + end end - scope.references! reflection_scope.values[:references] - if scope.eager_loading? && order_values = reflection_scope.values[:order] + scope.references! values[:references] + if scope.eager_loading? && order_values = values[:order] scope = scope.order(order_values) end end -- cgit v1.2.3 From db3ff259ea7c9b4c3660c0476e847907f90b762e Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Sun, 11 Jun 2017 20:13:21 +0900 Subject: Fix eager loading association with scope including joins Fixes #28324. --- .../associations/join_dependency/join_association.rb | 14 ++++++++++---- activerecord/lib/active_record/reflection.rb | 18 +++++++++++------- 2 files changed, 21 insertions(+), 11 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb index d0c1848079..b14ddfeeeb 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb @@ -34,13 +34,19 @@ module ActiveRecord table = tables.shift klass = reflection.klass - join_scope = reflection.join_scope(table, foreign_table, foreign_klass) - - binds.concat join_scope.bound_attributes - constraint = join_scope.arel.constraints + constraint = reflection.build_join_constraint(table, foreign_table) joins << table.create_join(table, table.create_on(constraint), join_type) + join_scope = reflection.join_scope(table, foreign_klass) + + if join_scope.arel.constraints.any? + binds.concat join_scope.bound_attributes + joins.concat join_scope.arel.join_sources + right = joins.last.right + right.expr = right.expr.and(join_scope.arel.constraints) + end + # The current table in this iteration becomes the foreign table in the next foreign_table, foreign_klass = table, klass end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 8ff2f50fdb..a453ca55c7 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -185,19 +185,23 @@ module ActiveRecord end deprecate :scope_chain - def join_scope(table, foreign_table, foreign_klass) - predicate_builder = predicate_builder(table) - scope_chain_items = join_scopes(table, predicate_builder) - klass_scope = klass_join_scope(table, predicate_builder) - + def build_join_constraint(table, foreign_table) key = join_keys.key foreign_key = join_keys.foreign_key - klass_scope.where!(table[key].eq(foreign_table[foreign_key])) + constraint = table[key].eq(foreign_table[foreign_key]) if klass.finder_needs_type_condition? - klass_scope.where!(klass.send(:type_condition, table)) + table.create_and([constraint, klass.send(:type_condition, table)]) + else + constraint end + end + + def join_scope(table, foreign_klass) + predicate_builder = predicate_builder(table) + scope_chain_items = join_scopes(table, predicate_builder) + klass_scope = klass_join_scope(table, predicate_builder) if type klass_scope.where!(type => foreign_klass.base_class.sti_name) -- cgit v1.2.3