Class: ViewModel::ActiveRecord::Cache

Inherits:
Object
  • Object
show all
Defined in:
lib/view_model/active_record/cache.rb

Overview

Cache for ViewModels that wrap ActiveRecord models.

Defined Under Namespace

Modules: CacheableView Classes: CacheWorker, StaleCachedReference, UncacheableViewModelError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(viewmodel_class, cache_group: nil) ⇒ Cache

If cache_group: is specified, it must be a group of a single key: ‘:id`



52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/view_model/active_record/cache.rb', line 52

def initialize(viewmodel_class, cache_group: nil)
  @viewmodel_class = viewmodel_class

  @cache_group = cache_group || create_default_cache_group
  @migrated_cache_group = @cache_group.register_child_group(:migrated, :version)

  # /viewname/:id/viewname-currentversion
  @cache = @cache_group.register_cache(cache_name)

  # /viewname/:id/migrated/:oldversion/viewname-currentversion
  @migrated_cache = @migrated_cache_group.register_cache(cache_name)
end

Instance Attribute Details

#viewmodel_classObject (readonly)

Returns the value of attribute viewmodel_class.



12
13
14
# File 'lib/view_model/active_record/cache.rb', line 12

def viewmodel_class
  @viewmodel_class
end

Class Method Details

.render_from_cache(viewmodel_class, ids, initial_viewmodels: nil, migration_versions: {}, locked: false, serialize_context: viewmodel_class.new_serialize_context) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/view_model/active_record/cache.rb', line 32

def render_from_cache(viewmodel_class, ids, initial_viewmodels: nil, migration_versions: {}, locked: false, serialize_context: viewmodel_class.new_serialize_context)
  ignore_existing = false
  begin
    worker = CacheWorker.new(migration_versions: migration_versions, serialize_context: serialize_context, ignore_existing: ignore_existing)
    worker.render_from_cache(viewmodel_class, ids, initial_viewmodels: initial_viewmodels, locked: locked)
  rescue StaleCachedReference
    # If the cache contents contained a unresolvable stale reference, retry
    # while ignoring existing cached values (thereby updating the cache). This
    # will have the side-effect of duplicate Before/AfterVisit callbacks.
    if ignore_existing
      raise
    else
      ignore_existing = true
      retry
    end
  end
end

.render_viewmodels_from_cache(viewmodels, migration_versions: {}, locked: false, serialize_context: nil) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/view_model/active_record/cache.rb', line 15

def render_viewmodels_from_cache(viewmodels, migration_versions: {}, locked: false, serialize_context: nil)
  if viewmodels.empty?
    return [], {}
  end

  ids = viewmodels.map(&:id)
  # ideally the roots wouldn't have to all be the same type
  viewmodel_class = viewmodels.first.class
  serialize_context ||= viewmodel_class.new_serialize_context

  render_from_cache(viewmodel_class, ids,
                    initial_viewmodels: viewmodels,
                    migration_versions: migration_versions,
                    locked: locked,
                    serialize_context: serialize_context)
end

Instance Method Details

#cache_for(migration_version) ⇒ Object



348
349
350
351
352
353
354
# File 'lib/view_model/active_record/cache.rb', line 348

def cache_for(migration_version)
  if migration_version
    @migrated_cache
  else
    @cache
  end
end

#cache_versionObject



380
381
382
383
384
385
386
# File 'lib/view_model/active_record/cache.rb', line 380

def cache_version
  @cache_version ||=
    begin
      versions = @viewmodel_class.deep_schema_version(include_referenced: false)
      ViewModel.schema_hash(versions)
    end
end

#clearObject



75
76
77
# File 'lib/view_model/active_record/cache.rb', line 75

def clear
  @cache_group.invalidate_cache_group
end

#delete(*ids) ⇒ Object

Handles being called with either ids or model/viewmodel objects



66
67
68
69
70
71
72
73
# File 'lib/view_model/active_record/cache.rb', line 66

def delete(*ids)
  ids.each do |id|
    id = id.id if id.respond_to?(:id)
    raise ArgumentError.new unless id.is_a?(Numeric) || id.is_a?(String)

    @cache_group.delete_all(@cache.key.new(id))
  end
end

#fetch(ids, initial_viewmodels: nil, migration_versions: {}, locked: false, serialize_context: @viewmodel_class.new_serialize_context) ⇒ Object

Deprecated.

Replaced by class methods



86
87
88
89
90
# File 'lib/view_model/active_record/cache.rb', line 86

def fetch(ids, initial_viewmodels: nil, migration_versions: {}, locked: false, serialize_context: @viewmodel_class.new_serialize_context)
  self.class.render_from_cache(@viewmodel_class, ids,
                               initial_viewmodels: initial_viewmodels, locked: locked,
                               migration_versions: migration_versions, serialize_context: serialize_context)
end

#fetch_by_viewmodel(viewmodels, migration_versions: {}, locked: false, serialize_context: @viewmodel_class.new_serialize_context) ⇒ Object

Deprecated.

Replaced by class methods



80
81
82
83
# File 'lib/view_model/active_record/cache.rb', line 80

def fetch_by_viewmodel(viewmodels, migration_versions: {}, locked: false, serialize_context: @viewmodel_class.new_serialize_context)
  ids = viewmodels.map(&:id)
  fetch(ids, initial_viewmodels: viewmodels, migration_versions: migration_versions, locked: locked, serialize_context: serialize_context)
end

#id_for(key) ⇒ Object



364
365
366
# File 'lib/view_model/active_record/cache.rb', line 364

def id_for(key)
  key[:id]
end

#key_for(id, migration_version) ⇒ Object



356
357
358
359
360
361
362
# File 'lib/view_model/active_record/cache.rb', line 356

def key_for(id, migration_version)
  if migration_version
    @migrated_cache.key.new(id, migration_version)
  else
    @cache.key.new(id)
  end
end

#load(ids, migration_version) ⇒ Object



374
375
376
377
378
# File 'lib/view_model/active_record/cache.rb', line 374

def load(ids, migration_version)
  keys = ids.map { |id| key_for(id, migration_version) }
  results = cache_for(migration_version).read_multi(keys)
  results.transform_keys! { |key| id_for(key) }
end

#migrated_cache_version(migration_versions) ⇒ Object



388
389
390
391
392
393
394
395
396
397
398
# File 'lib/view_model/active_record/cache.rb', line 388

def migrated_cache_version(migration_versions)
  versions = ViewModel::Migrator.migrated_deep_schema_version(viewmodel_class, migration_versions, include_referenced: false)
  version_hash = ViewModel.schema_hash(versions)

  if version_hash == cache_version
    # no migrations affect this view
    nil
  else
    version_hash
  end
end

#store(id, migration_version, data_serialization, ref_cache) ⇒ Object

Save the provided serialization and reference data in the cache



369
370
371
372
# File 'lib/view_model/active_record/cache.rb', line 369

def store(id, migration_version, data_serialization, ref_cache)
  key = key_for(id, migration_version)
  cache_for(migration_version).write(key, { data: data_serialization, ref_cache: ref_cache })
end