You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# frozen_string_literal: truerequire"bundler/inline"gemfile(true)dosource"https://rubygems.org"git_source(:github){ |repo| "https://github.com/#{repo}.git"}gem"rails",github: "rails/rails",branch: "main"gem"sqlite3"endrequire"active_record"require"active_support/testing/assertions"require"active_record/testing/query_assertions"require"minitest/autorun"require"logger"# This connection will do for database-independent bug reports.ActiveRecord::Base.establish_connection(adapter: "sqlite3",database: ":memory:")ActiveRecord::Base.logger=Logger.new(STDOUT)ActiveRecord::Schema.definedocreate_table:services,force: truedo |t|
t.string:name,null: falseendcreate_table:service_logs,force: truedo |t|
t.references:service,null: false,foreign_key: trueendcreate_table:charges,force: truedo |t|
t.references:service_log,null: false,foreign_key: trueendendclassService < ActiveRecord::Basehas_many:service_logsendclassServiceLog < ActiveRecord::Basebelongs_to:service,inverse_of: :service_logshas_one:chargeendclassCharge < ActiveRecord::Basebelongs_to:service_log,inverse_of: :chargehas_one:service,through: :service_logendclassBugTest < Minitest::TestincludeActiveSupport::Testing::AssertionsincludeActiveRecord::Assertions::QueryAssertionsdeftest_has_one_through_uses_preloaded_recordservice=Service.create!(name: 'Foobar')service_log=ServiceLog.create!(service:)charge=Charge.new(service_log: service_log)# this worksassert_no_queries{charge.service_log.service}# this failsassert_no_queries{charge.service}endend
Expected behavior
I'd expect that has_one through: ... defines a method that uses an already loaded join record if possible, to avoid redundant (and often N+1) queries).
Actual behavior
The generated method will load the associated record directly, even if it has already been preloaded in the join model.
I've tried to keep the test case above super clear, but my actual use case looks something like this:
The preload loads the small number of Service records involved, but accessing Charge#service causes N+1 queries as each charge loads the service independently again.
System configuration
Rails version: main, 7.0, 7.1
Ruby version: 3.1.4
The text was updated successfully, but these errors were encountered:
grncdr
changed the title
has_one :through associations ignore preloaded recordhas_one :through associations ignore preloaded records
May 14, 2024
Steps to reproduce
Expected behavior
I'd expect that
has_one through: ...
defines a method that uses an already loaded join record if possible, to avoid redundant (and often N+1) queries).Actual behavior
The generated method will load the associated record directly, even if it has already been preloaded in the join model.
I've tried to keep the test case above super clear, but my actual use case looks something like this:
The
preload
loads the small number ofService
records involved, but accessingCharge#service
causes N+1 queries as each charge loads the service independently again.System configuration
Rails version:
main
, 7.0, 7.1Ruby version: 3.1.4
The text was updated successfully, but these errors were encountered: