diff --git a/lib/chrono_model/patches/preloader.rb b/lib/chrono_model/patches/preloader.rb index 1627aeaf..4de25ea5 100644 --- a/lib/chrono_model/patches/preloader.rb +++ b/lib/chrono_model/patches/preloader.rb @@ -6,15 +6,19 @@ module Patches # and it is ugly :-(. # module Preloader - attr_reader :options + attr_reader :chronomodel_options # We overwrite the initializer in order to pass the +as_of_time+ # parameter above in the build_preloader # - def initialize(options = {}) - @options = options.freeze - if ActiveRecord::VERSION::STRING >= '7.0' - super(associate_by_default: true, **options) + def initialize(**options) + @chronomodel_options = options.extract!(:as_of_time, :model) + options[:scope] = chronomodel_scope(options[:scope]) if options.key?(:scope) + + if options.empty? + super() + else + super **options end end @@ -40,17 +44,20 @@ def initialize(options = {}) # so we use it directly. # def preload(records, associations, given_preload_scope = nil) - if options[:as_of_time] - preload_scope = given_preload_scope || - ChronoModel::Patches::AsOfTimeRelation.new(options[:model]) + super records, associations, chronomodel_scope(given_preload_scope) + end + + private - preload_scope.as_of_time!(options[:as_of_time]) - elsif given_preload_scope.respond_to?(:as_of_time) - preload_scope = given_preload_scope + def chronomodel_scope(given_preload_scope) + preload_scope = given_preload_scope + if chronomodel_options[:as_of_time] + preload_scope ||= ChronoModel::Patches::AsOfTimeRelation.new(chronomodel_options[:model]) + preload_scope.as_of_time!(chronomodel_options[:as_of_time]) end - super records, associations, preload_scope + preload_scope end module Association diff --git a/lib/chrono_model/patches/relation.rb b/lib/chrono_model/patches/relation.rb index e94ec122..dad976f8 100644 --- a/lib/chrono_model/patches/relation.rb +++ b/lib/chrono_model/patches/relation.rb @@ -5,22 +5,15 @@ module Relation include ChronoModel::Patches::AsOfTimeHolder def preload_associations(records) # :nodoc: - return super if ActiveRecord::VERSION::STRING < '7.0' + return super unless ActiveRecord::Associations::Preloader.instance_methods.include?(:call) preload = preload_values preload += includes_values unless eager_loading? scope = strict_loading_value ? StrictLoadingScope : nil preload.each do |associations| - if as_of_time - ## the tree structure of preloading ensure that children are loaded from history - klass = if associations.is_a? Hash - associations.keys[0].to_s.classify.constantize - else - associations.to_s.classify.constantize - end - scope = klass.as_of(as_of_time) if klass.respond_to?(:as_of) - end - ActiveRecord::Associations::Preloader.new(records: records, associations: associations, scope: scope).call + ActiveRecord::Associations::Preloader.new( + records: records, associations: associations, scope: scope, model: model, as_of_time: as_of_time + ).call end end diff --git a/spec/chrono_model/time_machine/as_of_spec.rb b/spec/chrono_model/time_machine/as_of_spec.rb index 39630e44..e7e23758 100644 --- a/spec/chrono_model/time_machine/as_of_spec.rb +++ b/spec/chrono_model/time_machine/as_of_spec.rb @@ -106,6 +106,8 @@ it { expect(Foo.as_of($t.foo.ts[1]).includes(:bars).first.bars).to eq [] } it { expect(Foo.as_of($t.foo.ts[2]).includes(:bars).first.bars).to eq [$t.bar] } + it { expect(Foo.as_of($t.foo.ts[0]).includes(:goo).first).to eq $t.foo } + it { expect(Foo.as_of($t.bar.ts[0]).includes(:bars).first.bars.first.name).to eq 'bar' } it { expect(Foo.as_of($t.bar.ts[1]).includes(:bars).first.bars.first.name).to eq 'foo bar' } it { expect(Foo.as_of($t.bar.ts[2]).includes(:bars).first.bars.first.name).to eq 'bar bar' } diff --git a/spec/support/time_machine/structure.rb b/spec/support/time_machine/structure.rb index 1c116364..01eeccae 100644 --- a/spec/support/time_machine/structure.rb +++ b/spec/support/time_machine/structure.rb @@ -22,6 +22,7 @@ module ChronoTest::TimeMachine adapter.create_table 'foos', :temporal => true do |t| t.string :name t.integer :fooity + t.references :goo end class ::Foo < ActiveRecord::Base @@ -29,6 +30,14 @@ class ::Foo < ActiveRecord::Base has_many :bars has_many :sub_bars, :through => :bars + + belongs_to :goo, class_name: 'FooGoo', optional: true + end + + class ::FooGoo < ActiveRecord::Base + include ChronoModel::TimeGate + + has_many :foos, inverse_of: :goo end class ::Boo < ActiveRecord::Base @@ -61,6 +70,10 @@ class ::Moo < ActiveRecord::Base t.references :boo end + adapter.create_table 'foo_goos' do |t| + t.string :name + end + class ::Bar < ActiveRecord::Base include ChronoModel::TimeMachine