Skip to content

Commit

Permalink
Merge pull request rails#40056 from kamipo/fix_preloader_associate_by…
Browse files Browse the repository at this point in the history
…_default

Fix preloader to associate preloaded records by default
  • Loading branch information
kamipo authored and berowar committed May 18, 2021
1 parent 76b226f commit a876c2f
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 14 deletions.
8 changes: 6 additions & 2 deletions activerecord/lib/active_record/associations/preloader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ def preload(records, associations, preload_scope = nil)
end
end

def initialize(associate_by_default: true)
@associate_by_default = associate_by_default
end

private
# Loads all the given data into +records+ for the +association+.
def preloaders_on(association, records, scope, polymorphic_parent = false)
Expand Down Expand Up @@ -142,7 +146,7 @@ def preloaders_for_one(association, records, scope, polymorphic_parent)

def preloaders_for_reflection(reflection, records, scope)
records.group_by { |record| record.association(reflection.name).klass }.map do |rhs_klass, rs|
preloader_for(reflection, rs).new(rhs_klass, rs, reflection, scope).run
preloader_for(reflection, rs).new(rhs_klass, rs, reflection, scope, @associate_by_default).run
end
end

Expand All @@ -157,7 +161,7 @@ def grouped_records(association, records, polymorphic_parent)
end

class AlreadyLoaded # :nodoc:
def initialize(klass, owners, reflection, preload_scope)
def initialize(klass, owners, reflection, preload_scope, associate_by_default = true)
@owners = owners
@reflection = reflection
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,22 @@ module ActiveRecord
module Associations
class Preloader
class Association #:nodoc:
def initialize(klass, owners, reflection, preload_scope)
def initialize(klass, owners, reflection, preload_scope, associate_by_default = true)
@klass = klass
@owners = owners.uniq(&:__id__)
@reflection = reflection
@preload_scope = preload_scope
@associate = associate_by_default || !preload_scope || preload_scope.empty_scope?
@model = owners.first && owners.first.class
end

def run
if !preload_scope || preload_scope.empty_scope?
owners.each do |owner|
associate_records_to_owner(owner, records_by_owner[owner] || [])
end
else
# Custom preload scope is used and
# the association can not be marked as loaded
# Loading into a Hash instead
records_by_owner
end
records = records_by_owner

owners.each do |owner|
associate_records_to_owner(owner, records[owner] || [])
end if @associate

self
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module ActiveRecord
module Associations
class Preloader
class ThroughAssociation < Association # :nodoc:
PRELOADER = ActiveRecord::Associations::Preloader.new
PRELOADER = ActiveRecord::Associations::Preloader.new(associate_by_default: false)

def initialize(*)
super
Expand Down
15 changes: 15 additions & 0 deletions activerecord/test/cases/associations_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -345,8 +345,23 @@ def test_requires_symbol_argument
end
end

class PreloaderTest < ActiveRecord::TestCase
fixtures :posts, :comments

def test_preload_with_scope
post = posts(:welcome)

preloader = ActiveRecord::Associations::Preloader.new
preloader.preload([post], :comments, Comment.where(body: "Thank you for the welcome"))

assert_predicate post.comments, :loaded?
assert_equal [comments(:greetings)], post.comments
end
end

class GeneratedMethodsTest < ActiveRecord::TestCase
fixtures :developers, :computers, :posts, :comments

def test_association_methods_override_attribute_methods_of_same_name
assert_equal(developers(:david), computers(:workstation).developer)
# this next line will fail if the attribute methods module is generated lazily
Expand Down

0 comments on commit a876c2f

Please sign in to comment.