From 0d7ab973e15b476ed42471395027e329f95c8951 Mon Sep 17 00:00:00 2001 From: "yuuji.yaginuma" Date: Fri, 3 Nov 2017 10:09:43 +0900 Subject: Remove unused classes * `HasManyThroughCantDissociateNewRecords` and `HasManyThroughCantAssociateNewRecords` are no longer used since f6b12c1. * `ReadOnlyAssociation` is no longer used since 0da426b. --- activerecord/lib/active_record/associations.rb | 30 -------------------------- 1 file changed, 30 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index bc7e288500..661605d3e5 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -140,26 +140,6 @@ module ActiveRecord class HasOneThroughCantAssociateThroughHasOneOrManyReflection < ThroughCantAssociateThroughHasOneOrManyReflection #:nodoc: end - class HasManyThroughCantAssociateNewRecords < ActiveRecordError #:nodoc: - def initialize(owner = nil, reflection = nil) - if owner && reflection - super("Cannot associate new records through '#{owner.class.name}##{reflection.name}' on '#{reflection.source_reflection.class_name rescue nil}##{reflection.source_reflection.name rescue nil}'. Both records must have an id in order to create the has_many :through record associating them.") - else - super("Cannot associate new records.") - end - end - end - - class HasManyThroughCantDissociateNewRecords < ActiveRecordError #:nodoc: - def initialize(owner = nil, reflection = nil) - if owner && reflection - super("Cannot dissociate new records through '#{owner.class.name}##{reflection.name}' on '#{reflection.source_reflection.class_name rescue nil}##{reflection.source_reflection.name rescue nil}'. Both records must have an id in order to delete the has_many :through record associating them.") - else - super("Cannot dissociate new records.") - end - end - end - class ThroughNestedAssociationsAreReadonly < ActiveRecordError #:nodoc: def initialize(owner = nil, reflection = nil) if owner && reflection @@ -189,16 +169,6 @@ module ActiveRecord end end - class ReadOnlyAssociation < ActiveRecordError #:nodoc: - def initialize(reflection = nil) - if reflection - super("Cannot add to a has_many :through association. Try adding to #{reflection.through_reflection.name.inspect}.") - else - super("Read-only reflection error.") - end - end - end - # This error is raised when trying to destroy a parent instance in N:1 or 1:1 associations # (has_many, has_one) when there is at least 1 child associated instance. # ex: if @project.tasks.size > 0, DeleteRestrictionError will be raised when trying to destroy @project -- cgit v1.2.3 From e3a295664681ea0480a9c95f6bfc776a113ff926 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Wed, 1 Nov 2017 10:36:47 +0900 Subject: Ensure `apply_join_dependency` for `collection_cache_key` if eager-loading is needed Fixes #30315. --- activerecord/lib/active_record/collection_cache_key.rb | 3 +++ activerecord/lib/active_record/relation/calculations.rb | 4 ++-- activerecord/lib/active_record/relation/finder_methods.rb | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/collection_cache_key.rb b/activerecord/lib/active_record/collection_cache_key.rb index f3e6516414..88b398ad45 100644 --- a/activerecord/lib/active_record/collection_cache_key.rb +++ b/activerecord/lib/active_record/collection_cache_key.rb @@ -12,6 +12,9 @@ module ActiveRecord timestamp = collection.max_by(×tamp_column)._read_attribute(timestamp_column) end else + if collection.eager_loading? + collection = collection.send(:apply_join_dependency) + end column_type = type_for_attribute(timestamp_column.to_s) column = connection.column_name_from_arel_node(collection.arel_attribute(timestamp_column)) select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp" diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 116bddce85..11256ab3d9 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -130,7 +130,7 @@ module ActiveRecord # end def calculate(operation, column_name) if has_include?(column_name) - relation = apply_join_dependency(construct_join_dependency) + relation = apply_join_dependency relation.distinct! if operation.to_s.downcase == "count" relation.calculate(operation, column_name) @@ -180,7 +180,7 @@ module ActiveRecord end if has_include?(column_names.first) - relation = apply_join_dependency(construct_join_dependency) + relation = apply_join_dependency relation.pluck(*column_names) else relation = spawn diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 707245bab2..18566b5662 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -394,7 +394,7 @@ module ActiveRecord ) end - def apply_join_dependency(join_dependency) + def apply_join_dependency(join_dependency = construct_join_dependency) relation = except(:includes, :eager_load, :preload).joins!(join_dependency) if using_limitable_reflections?(join_dependency.reflections) -- cgit v1.2.3 From 8a2ee3d8c6921ce34e597658e3f2b43b41423d1d Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Mon, 16 Oct 2017 01:33:40 +0900 Subject: Ensure `apply_join_dependency` for `update_all` and `delete_all` if eager-loading is needed If a relation has eager-loading values, `count` and `exists?` works properly, but `update_all` and `delete_all` doesn't work due to missing `apply_join_dependency`. It should be applied to work consistently. Fixes #28863. --- activerecord/lib/active_record/relation.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 997cfe4b5e..7615fb6ee9 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -359,6 +359,11 @@ module ActiveRecord def update_all(updates) raise ArgumentError, "Empty list of attributes to change" if updates.blank? + if eager_loading? + relation = apply_join_dependency + return relation.update_all(updates) + end + stmt = Arel::UpdateManager.new stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates)) @@ -423,6 +428,11 @@ module ActiveRecord raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}") end + if eager_loading? + relation = apply_join_dependency + return relation.delete_all + end + stmt = Arel::DeleteManager.new stmt.from(table) -- cgit v1.2.3 From e617fb57f5a388d5f0a47fd5e576588dd10066b0 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Mon, 30 Oct 2017 23:55:48 +0900 Subject: Fix preloading polymorphic association when through association has already loaded If through association has already loaded, `source_type` is ignored to loaded through records. The loaded records should be filtered by `source_type` in that case. Fixes #30904. --- .../associations/preloader/through_association.rb | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb index fa32cc5553..5bd49b041a 100644 --- a/activerecord/lib/active_record/associations/preloader/through_association.rb +++ b/activerecord/lib/active_record/associations/preloader/through_association.rb @@ -13,18 +13,30 @@ module ActiveRecord end def associated_records_by_owner(preloader) + already_loaded = owners.first.association(through_reflection.name).loaded? through_scope = through_scope() - preloader.preload(owners, - through_reflection.name, - through_scope) + unless already_loaded + preloader.preload(owners, through_reflection.name, through_scope) + end through_records = owners.map do |owner| center = owner.association(through_reflection.name).target [owner, Array(center)] end - reset_association(owners, through_reflection.name, through_scope) + if already_loaded + if source_type = reflection.options[:source_type] + through_records.map! do |owner, center| + center = center.select do |record| + record[reflection.foreign_type] == source_type + end + [owner, center] + end + end + else + reset_association(owners, through_reflection.name, through_scope) + end middle_records = through_records.flat_map(&:last) -- cgit v1.2.3 From e0bef22665f93e88f6b2f3ac6bd55543ed0d6343 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Mon, 6 Nov 2017 06:40:36 +0900 Subject: Fix preloading polymorphic multi-level through association This is partially fixed by e617fb57 when through association has already loaded. Otherwise, second level through association should respect `preload_scope`. Fixes #30242. Closes #30076. [Ryuta Kamizono & CicholGricenchos] --- .../active_record/associations/preloader/through_association.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb index 5bd49b041a..b16fca7dc9 100644 --- a/activerecord/lib/active_record/associations/preloader/through_association.rb +++ b/activerecord/lib/active_record/associations/preloader/through_association.rb @@ -40,7 +40,11 @@ module ActiveRecord middle_records = through_records.flat_map(&:last) - reflection_scope = reflection_scope() if reflection.scope + if preload_scope + reflection_scope = reflection_scope().merge(preload_scope) + elsif reflection.scope + reflection_scope = reflection_scope() + end preloaders = preloader.preload(middle_records, source_reflection.name, @@ -70,6 +74,8 @@ module ActiveRecord rhs_records end end + end.tap do + reset_association(middle_records, source_reflection.name, preload_scope) end end -- cgit v1.2.3 From ffc1ed9bd54f3cf746f7ddf798e000fc025edef6 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Mon, 6 Nov 2017 08:29:40 +0900 Subject: `scoping` should respect current class and STI constraint (#29199) A relation includes `klass`, so it can not be used as it is if current class is different from `current_scope.klass`. It should be created new relation by current class to respect the klass and STI constraint. Fixes #17603. Fixes #23576. --- activerecord/lib/active_record/scoping/named.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/scoping/named.rb b/activerecord/lib/active_record/scoping/named.rb index 6fa096c1fe..310af72c41 100644 --- a/activerecord/lib/active_record/scoping/named.rb +++ b/activerecord/lib/active_record/scoping/named.rb @@ -24,8 +24,14 @@ module ActiveRecord # You can define a scope that applies to all finders using # {default_scope}[rdoc-ref:Scoping::Default::ClassMethods#default_scope]. def all + current_scope = self.current_scope + if current_scope - current_scope.clone + if self == current_scope.klass + current_scope.clone + else + relation.merge!(current_scope) + end else default_scoped end -- cgit v1.2.3 From edcc0a714d911468caf7db0879fc7a3d1185ee3c Mon Sep 17 00:00:00 2001 From: Bogdan Gusiev Date: Mon, 6 Nov 2017 17:32:54 +0200 Subject: Refactor Preloader Code --- .../associations/preloader/association.rb | 4 +- .../associations/preloader/has_many_through.rb | 10 -- .../associations/preloader/through_association.rb | 107 ++++++++------------- 3 files changed, 40 insertions(+), 81 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 607d376a08..b0c41c7d5f 100644 --- a/activerecord/lib/active_record/associations/preloader/association.rb +++ b/activerecord/lib/active_record/associations/preloader/association.rb @@ -17,7 +17,7 @@ module ActiveRecord end def run(preloader) - associated_records_by_owner(preloader).each do |owner, records| + associated_records_by_owner(preloader) do |owner, records| associate_records_to_owner(owner, records) end end @@ -41,7 +41,7 @@ module ActiveRecord end owners.each_with_object({}) do |owner, result| - result[owner] = records[convert_key(owner[owner_key_name])] || [] + yield(owner, records[convert_key(owner[owner_key_name])] || []) end end diff --git a/activerecord/lib/active_record/associations/preloader/has_many_through.rb b/activerecord/lib/active_record/associations/preloader/has_many_through.rb index 0639fdca44..3e17d07a33 100644 --- a/activerecord/lib/active_record/associations/preloader/has_many_through.rb +++ b/activerecord/lib/active_record/associations/preloader/has_many_through.rb @@ -5,16 +5,6 @@ module ActiveRecord class Preloader class HasManyThrough < CollectionAssociation #:nodoc: include ThroughAssociation - - def associated_records_by_owner(preloader) - records_by_owner = super - - if reflection_scope.distinct_value - records_by_owner.each_value(&:uniq!) - end - - records_by_owner - end 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 b16fca7dc9..1bb7e98231 100644 --- a/activerecord/lib/active_record/associations/preloader/through_association.rb +++ b/activerecord/lib/active_record/associations/preloader/through_association.rb @@ -13,86 +13,45 @@ module ActiveRecord end def associated_records_by_owner(preloader) - already_loaded = owners.first.association(through_reflection.name).loaded? - through_scope = through_scope() - - unless already_loaded - preloader.preload(owners, through_reflection.name, through_scope) - end - - through_records = owners.map do |owner| - center = owner.association(through_reflection.name).target - [owner, Array(center)] - end + already_loaded = owners.first.association(through_reflection.name).loaded? + through_scope = through_scope() + reflection_scope = target_reflection_scope + through_preloaders = preloader.preload(owners, through_reflection.name, through_scope) + middle_records = through_preloaders.flat_map(&:preloaded_records) + preloaders = preloader.preload(middle_records, source_reflection.name, reflection_scope) + @preloaded_records = preloaders.flat_map(&:preloaded_records) - if already_loaded - if source_type = reflection.options[:source_type] - through_records.map! do |owner, center| - center = center.select do |record| + owners.each do |owner| + through_records = Array(owner.association(through_reflection.name).target) + if already_loaded + if source_type = reflection.options[:source_type] + through_records = through_records.select do |record| record[reflection.foreign_type] == source_type end - [owner, center] end + else + owner.association(through_reflection.name).reset if through_scope end - else - reset_association(owners, through_reflection.name, through_scope) - end - - middle_records = through_records.flat_map(&:last) - - if preload_scope - reflection_scope = reflection_scope().merge(preload_scope) - elsif reflection.scope - reflection_scope = reflection_scope() - end - - preloaders = preloader.preload(middle_records, - source_reflection.name, - reflection_scope) - - @preloaded_records = preloaders.flat_map(&:preloaded_records) - - middle_to_pl = preloaders.each_with_object({}) do |pl, h| - pl.owners.each { |middle| - h[middle] = pl - } - end - - through_records.each_with_object({}) do |(lhs, center), records_by_owner| - pl_to_middle = center.group_by { |record| middle_to_pl[record] } - - records_by_owner[lhs] = pl_to_middle.flat_map do |pl, middles| - rhs_records = middles.flat_map { |r| - r.association(source_reflection.name).target - }.compact - - # Respect the order on `reflection_scope` if it exists, else use the natural order. - if reflection_scope && !reflection_scope.order_values.empty? - @id_map ||= id_to_index_map @preloaded_records - rhs_records.sort_by { |rhs| @id_map[rhs] } - else - rhs_records - end + result = through_records.flat_map do |record| + association = record.association(source_reflection.name) + target = association.target + association.reset if preload_scope + target end - end.tap do - reset_association(middle_records, source_reflection.name, preload_scope) + result.compact! + if reflection_scope + result.sort_by! { |rhs| preload_index[rhs] } if reflection_scope.order_values.any? + result.uniq! if reflection_scope.distinct_value + end + yield(owner, result) end end private - def id_to_index_map(ids) - id_map = {} - ids.each_with_index { |id, index| id_map[id] = index } - id_map - end - - def reset_association(owners, association_name, should_reset) - # Don't cache the association - we would only be caching a subset - if should_reset - owners.each { |owner| - owner.association(association_name).reset - } + def preload_index + @preload_index ||= @preloaded_records.each_with_object({}).with_index do |(id, result), index| + result[id] = index end end @@ -133,6 +92,16 @@ module ActiveRecord scope unless scope.empty_scope? end + + def target_reflection_scope + if preload_scope + reflection_scope.merge(preload_scope) + elsif reflection.scope + reflection_scope + else + nil + end + end end end end -- cgit v1.2.3 From 01c703248396528d9f3398d0f9d0143831e9d0dc Mon Sep 17 00:00:00 2001 From: Keenan Brock Date: Thu, 9 Mar 2017 11:48:44 -0500 Subject: Properly check transaction in persistence ``` [NoMethodError]: undefined method `state' for nil:NilClass Method:[rescue in block in refresh] ``` In `within_new_transaction`, there is the possibility that `begin_transaction` returns a `nil`. (i.e.: so `transaction = nil`) So this method is checking `transaction` for nil in 2 spots. Unfortunately, there is one line that is not checking `transaction` for `nil` That line, `commit_transaction`, throws an exception for us in AR 5.0.0.1 The problem with the method is finally realized in the error checking itself. it calls `transaction.state` (i.e.: nil.state) and that is the final exception raised. The actual underlying (user) issue is hidden by this line. Solution is test transaction for nil. --- .../lib/active_record/connection_adapters/abstract/transaction.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb index 147e16e9fa..d9ac8db6a8 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb @@ -240,7 +240,7 @@ module ActiveRecord rollback_transaction if transaction else begin - commit_transaction + commit_transaction if transaction rescue Exception rollback_transaction(transaction) unless transaction.state.completed? raise -- cgit v1.2.3 From 90fe2a42f0b68a66e970169d38e91a0126de7d3e Mon Sep 17 00:00:00 2001 From: bogdanvlviv Date: Tue, 26 Sep 2017 00:10:17 +0300 Subject: Fix `bin/rails db:migrate` with specified `VERSION` Ensure that `bin/rails db:migrate` with specified `VERSION` reverts all migrations only if `VERSION` is `0`. Raise error if target migration doesn't exist. --- activerecord/lib/active_record/migration.rb | 2 +- .../lib/active_record/railties/databases.rake | 19 +++++++++++++++---- .../lib/active_record/tasks/database_tasks.rb | 15 ++++++++++++--- 3 files changed, 28 insertions(+), 8 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 1485687053..d12a979a7f 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -1224,7 +1224,7 @@ module ActiveRecord # Return true if a valid version is not provided. def invalid_target? - !target && @target_version && @target_version > 0 + @target_version && @target_version != 0 && !target end def execute_migration_in_transaction(migration, direction) diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 723272b4b2..3bca2982e0 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -97,16 +97,27 @@ db_namespace = namespace :db do task up: [:environment, :load_config] do raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty? - version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil - ActiveRecord::Migrator.run(:up, ActiveRecord::Tasks::DatabaseTasks.migrations_paths, version) + ActiveRecord::Tasks::DatabaseTasks.check_target_version + + ActiveRecord::Migrator.run( + :up, + ActiveRecord::Tasks::DatabaseTasks.migrations_paths, + ActiveRecord::Tasks::DatabaseTasks.target_version + ) db_namespace["_dump"].invoke end # desc 'Runs the "down" for a given migration VERSION.' task down: [:environment, :load_config] do raise "VERSION is required - To go down one migration, use db:rollback" if !ENV["VERSION"] || ENV["VERSION"].empty? - version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil - ActiveRecord::Migrator.run(:down, ActiveRecord::Tasks::DatabaseTasks.migrations_paths, version) + + ActiveRecord::Tasks::DatabaseTasks.check_target_version + + ActiveRecord::Migrator.run( + :down, + ActiveRecord::Tasks::DatabaseTasks.migrations_paths, + ActiveRecord::Tasks::DatabaseTasks.target_version + ) db_namespace["_dump"].invoke end diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb index ff388ff1f6..4657e51e6d 100644 --- a/activerecord/lib/active_record/tasks/database_tasks.rb +++ b/activerecord/lib/active_record/tasks/database_tasks.rb @@ -164,13 +164,12 @@ module ActiveRecord end def migrate - raise "Empty VERSION provided" if ENV["VERSION"] && ENV["VERSION"].empty? + check_target_version verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] != "false" : true - version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil scope = ENV["SCOPE"] verbose_was, Migration.verbose = Migration.verbose, verbose - Migrator.migrate(migrations_paths, version) do |migration| + Migrator.migrate(migrations_paths, target_version) do |migration| scope.blank? || scope == migration.scope end ActiveRecord::Base.clear_cache! @@ -178,6 +177,16 @@ module ActiveRecord Migration.verbose = verbose_was end + def check_target_version + if target_version && !(Migration::MigrationFilenameRegexp.match?(ENV["VERSION"]) || /\A\d+\z/.match?(ENV["VERSION"])) + raise "Invalid format of target version: `VERSION=#{ENV['VERSION']}`" + end + end + + def target_version + ENV["VERSION"].to_i if ENV["VERSION"] && !ENV["VERSION"].empty? + end + def charset_current(environment = env) charset ActiveRecord::Base.configurations[environment] end -- cgit v1.2.3 From 3f1695bb9c008b7cb1840e09e640f3ec0c59a564 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Tue, 7 Nov 2017 08:44:44 +0900 Subject: Remove useless `associated_records_by_owner` `associated_records_by_owner` had returned customizing result before calling `associate_records_to_owner` for through association subclasses. Since #22115, `associate_records_to_owner` is called in the method and not returned owner and result pairs. Removing the method will reduce method call and block call nesting. --- .../associations/preloader/association.rb | 22 ++++++++-------------- .../associations/preloader/through_association.rb | 4 ++-- 2 files changed, 10 insertions(+), 16 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 b0c41c7d5f..e77761692d 100644 --- a/activerecord/lib/active_record/associations/preloader/association.rb +++ b/activerecord/lib/active_record/associations/preloader/association.rb @@ -17,8 +17,14 @@ module ActiveRecord end def run(preloader) - associated_records_by_owner(preloader) do |owner, records| - associate_records_to_owner(owner, records) + records = load_records do |record| + owner = owners_by_key[convert_key(record[association_key_name])] + association = owner.association(reflection.name) + association.set_inverse_instance(record) + end + + owners.each do |owner| + associate_records_to_owner(owner, records[convert_key(owner[owner_key_name])] || []) end end @@ -33,18 +39,6 @@ module ActiveRecord reflection.join_foreign_key end - def associated_records_by_owner(preloader) - records = load_records do |record| - owner = owners_by_key[convert_key(record[association_key_name])] - association = owner.association(reflection.name) - association.set_inverse_instance(record) - end - - owners.each_with_object({}) do |owner, result| - yield(owner, records[convert_key(owner[owner_key_name])] || []) - end - end - def associate_records_to_owner(owner, records) raise NotImplementedError end diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb index 1bb7e98231..b1813ba66b 100644 --- a/activerecord/lib/active_record/associations/preloader/through_association.rb +++ b/activerecord/lib/active_record/associations/preloader/through_association.rb @@ -12,7 +12,7 @@ module ActiveRecord reflection.source_reflection end - def associated_records_by_owner(preloader) + def run(preloader) already_loaded = owners.first.association(through_reflection.name).loaded? through_scope = through_scope() reflection_scope = target_reflection_scope @@ -43,7 +43,7 @@ module ActiveRecord result.sort_by! { |rhs| preload_index[rhs] } if reflection_scope.order_values.any? result.uniq! if reflection_scope.distinct_value end - yield(owner, result) + associate_records_to_owner(owner, result) end end -- cgit v1.2.3 From 0c2cb880e34c943275758ca6a6ff84afa7a29fba Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Wed, 8 Nov 2017 20:08:19 +0900 Subject: Don't expose internal methods in `Preloader::ThroughAssociation` `through_reflection` and `source_reflection` are used only in the class. --- .../associations/preloader/through_association.rb | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb index b1813ba66b..762275fbad 100644 --- a/activerecord/lib/active_record/associations/preloader/through_association.rb +++ b/activerecord/lib/active_record/associations/preloader/through_association.rb @@ -4,14 +4,6 @@ module ActiveRecord module Associations class Preloader module ThroughAssociation #:nodoc: - def through_reflection - reflection.through_reflection - end - - def source_reflection - reflection.source_reflection - end - def run(preloader) already_loaded = owners.first.association(through_reflection.name).loaded? through_scope = through_scope() @@ -48,6 +40,13 @@ module ActiveRecord end private + def through_reflection + reflection.through_reflection + end + + def source_reflection + reflection.source_reflection + end def preload_index @preload_index ||= @preloaded_records.each_with_object({}).with_index do |(id, result), index| -- cgit v1.2.3 From 65aa0b7e3448f849a91b6f510b78d4303ff44dbc Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Wed, 8 Nov 2017 20:28:52 +0900 Subject: Don't expose accessors which are internal used only --- activerecord/lib/active_record/associations/preloader.rb | 5 +++-- activerecord/lib/active_record/associations/preloader/association.rb | 4 +++- 2 files changed, 6 insertions(+), 3 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 e1754d4a19..5a93a89d0a 100644 --- a/activerecord/lib/active_record/associations/preloader.rb +++ b/activerecord/lib/active_record/associations/preloader.rb @@ -166,8 +166,6 @@ module ActiveRecord end class AlreadyLoaded # :nodoc: - attr_reader :owners, :reflection - def initialize(klass, owners, reflection, preload_scope) @owners = owners @reflection = reflection @@ -178,6 +176,9 @@ module ActiveRecord def preloaded_records owners.flat_map { |owner| owner.association(reflection.name).target } end + + protected + attr_reader :owners, :reflection end # Returns a class containing the logic needed to load preload the data diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb index e77761692d..19c337dc39 100644 --- a/activerecord/lib/active_record/associations/preloader/association.rb +++ b/activerecord/lib/active_record/associations/preloader/association.rb @@ -4,7 +4,6 @@ module ActiveRecord module Associations class Preloader class Association #:nodoc: - attr_reader :owners, :reflection, :preload_scope, :model, :klass attr_reader :preloaded_records def initialize(klass, owners, reflection, preload_scope) @@ -28,6 +27,9 @@ module ActiveRecord end end + protected + attr_reader :owners, :reflection, :preload_scope, :model, :klass + private # The name of the key on the associated records def association_key_name -- cgit v1.2.3