Module: SecondLevelCache::ActiveRecord::Associations::Preloader

Defined in:
lib/second_level_cache/active_record/preloader.rb

Constant Summary collapse

RAILS6 =
::ActiveRecord.version >= ::Gem::Version.new("6")

Instance Method Summary collapse

Instance Method Details

#records_for(ids, &block) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/second_level_cache/active_record/preloader.rb', line 9

def records_for(ids, &block)
  return super unless klass.second_level_cache_enabled?
  return super unless reflection.is_a?(::ActiveRecord::Reflection::BelongsToReflection)
  return super if klass.default_scopes.present?

  map_cache_keys = ids.map { |id| klass.second_level_cache_key(id) }
  records_from_cache = ::SecondLevelCache.cache_store.read_multi(*map_cache_keys)

  record_marshals = if RAILS6
    RecordMarshal.load_multi(records_from_cache.values) do |record|
      # This block is copy from:
      # https://github.com/rails/rails/blob/6-0-stable/activerecord/lib/active_record/associations/preloader/association.rb#L101
      owner = owners_by_key[convert_key(record[association_key_name])].first
      association = owner.association(reflection.name)
      association.set_inverse_instance(record)
    end
  else
    RecordMarshal.load_multi(records_from_cache.values, &block)
  end

  # NOTICE
  # Rails.cache.read_multi return hash that has keys only hitted.
  # eg. Rails.cache.read_multi(1,2,3) => {2 => hit_value, 3 => hit_value}
  hitted_ids = record_marshals.map { |record| record.read_attribute(association_key_name).to_s }
  missed_ids = ids.map(&:to_s) - hitted_ids
  ActiveSupport::Notifications.instrument("preload.second_level_cache", key: association_key_name, hit: hitted_ids, miss: missed_ids)
  return SecondLevelCache::RecordRelation.new(record_marshals) if missed_ids.empty?

  records_from_db = super(missed_ids, &block)
  records_from_db.map { |r| write_cache(r) }

  SecondLevelCache::RecordRelation.new(records_from_db + record_marshals)
end