Module: ChronoModel::Patches::Preloader

Defined in:
lib/chrono_model/patches.rb

Overview

Patches ActiveRecord::Associations::Preloader to add support for temporal associations. This is tying itself to Rails internals and it is ugly :-(.

Defined Under Namespace

Modules: Association

Constant Summary collapse

NULL_RELATION =

See ActiveRecord::Associations::Preloader::NULL_RELATION

ActiveRecord::Associations::Preloader::NULL_RELATION

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options


100
101
102
# File 'lib/chrono_model/patches.rb', line 100

def options
  @options
end

Instance Method Details

#initialize(options = {}) ⇒ Object

We overwrite the initializer in order to pass the as_of_time parameter above in the build_preloader


105
106
107
# File 'lib/chrono_model/patches.rb', line 105

def initialize(options = {})
  @options = options.freeze
end

#preload(records, associations, given_preload_scope = nil) ⇒ Object

Patches the AR Preloader (lib/active_record/associations/preloader.rb) in order to carry around the as_of_time of the original invocation.

  • The records are the parent records where the association is defined

  • The associations are the association names involved in preloading

  • The given_preload_scope is the preloading scope, that is used only in the :through association and it holds the intermediate records through which the final associated records are eventually fetched.

As the preload_scope is passed around to all the different incarnations of the preloader strategies, we are using it to pass around the as_of_time of the original query invocation, so that preloaded records are preloaded honoring the as_of_time.

The preload_scope is not nil only for through associations, but the preloader interfaces expect it to be always defined, for consistency.

So, AR defines a NULL_RELATION constant to pass around for the association types that do not have a preload_scope. It quacks like a Relation, and it contains only the methods that are used by the other preloader methods. We use this NULL_RELATION to which we have added the `as_of_time!` holder method.

For `:through` associations, the given_preload_scope is already a Relation, that already has the as_of_time getters and setters, so we use it directly.


143
144
145
146
147
148
149
150
# File 'lib/chrono_model/patches.rb', line 143

def preload(records, associations, given_preload_scope = nil)
  if options.key?(:as_of_time)
    preload_scope = given_preload_scope || NULL_RELATION.dup
    preload_scope.as_of_time!(options[:as_of_time])
  end

  super records, associations, preload_scope
end