Class: PaperTrailHistory::TrackableModel

Inherits:
Object
  • Object
show all
Defined in:
app/models/paper_trail_history/trackable_model.rb

Overview

Model wrapper for trackable ActiveRecord classes with PaperTrail versioning

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(klass, cached_version_count = nil) ⇒ TrackableModel



8
9
10
11
12
# File 'app/models/paper_trail_history/trackable_model.rb', line 8

def initialize(klass, cached_version_count = nil)
  @klass = klass
  @name = klass.name
  @cached_version_count = cached_version_count
end

Instance Attribute Details

#cached_version_countObject (readonly)

Returns the value of attribute cached_version_count.



6
7
8
# File 'app/models/paper_trail_history/trackable_model.rb', line 6

def cached_version_count
  @cached_version_count
end

#klassObject (readonly)

Returns the value of attribute klass.



6
7
8
# File 'app/models/paper_trail_history/trackable_model.rb', line 6

def klass
  @klass
end

#nameObject (readonly)

Returns the value of attribute name.



6
7
8
# File 'app/models/paper_trail_history/trackable_model.rb', line 6

def name
  @name
end

Class Method Details

.allObject



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'app/models/paper_trail_history/trackable_model.rb', line 14

def self.all
  return @all_models if defined?(@all_models) && @all_models

  Rails.application.eager_load!

  # Use a Set to ensure uniqueness by class name
  trackable_classes = {}
  ObjectSpace.each_object(Class) do |klass|
    next unless klass < ActiveRecord::Base
    next if klass.abstract_class?
    next unless klass.included_modules.include?(PaperTrail::Model::InstanceMethods)

    # Only keep one instance per class name to avoid duplicates
    trackable_classes[klass.name] = new(klass)
  end

  @all_models = trackable_classes.values.sort_by(&:name)
end

.all_with_countsObject



33
34
35
36
37
38
39
# File 'app/models/paper_trail_history/trackable_model.rb', line 33

def self.all_with_counts
  models = all
  return models if models.empty?

  count_cache = build_count_cache(models)
  models_with_cached_counts(models, count_cache)
end

.build_count_cache(models) ⇒ Object



41
42
43
44
45
46
# File 'app/models/paper_trail_history/trackable_model.rb', line 41

def self.build_count_cache(models)
  models_by_version_class = models.group_by(&:version_class)
  count_cache = {}
  populate_count_cache(models_by_version_class, count_cache)
  count_cache
end

.cache_counts_for_models(models_for_class, counts, count_cache) ⇒ Object



60
61
62
63
64
# File 'app/models/paper_trail_history/trackable_model.rb', line 60

def self.cache_counts_for_models(models_for_class, counts, count_cache)
  models_for_class.each do |model|
    count_cache[model.name] = counts[model.item_type_for_versions] || 0
  end
end

.clear_cache!Object

Clear cached models (useful in development when adding new trackable models)



75
76
77
# File 'app/models/paper_trail_history/trackable_model.rb', line 75

def self.clear_cache!
  @all_models = nil
end

.fetch_version_counts(version_class, models_for_class) ⇒ Object



55
56
57
58
# File 'app/models/paper_trail_history/trackable_model.rb', line 55

def self.fetch_version_counts(version_class, models_for_class)
  item_types = models_for_class.map(&:item_type_for_versions)
  version_class.where(item_type: item_types).group(:item_type).count
end

.find(model_name) ⇒ Object



70
71
72
# File 'app/models/paper_trail_history/trackable_model.rb', line 70

def self.find(model_name)
  all.find { |model| model.name == model_name }
end

.models_with_cached_counts(models, count_cache) ⇒ Object



66
67
68
# File 'app/models/paper_trail_history/trackable_model.rb', line 66

def self.models_with_cached_counts(models, count_cache)
  models.map { |model| new(model.klass, count_cache[model.name]) }
end

.populate_count_cache(models_by_version_class, count_cache) ⇒ Object



48
49
50
51
52
53
# File 'app/models/paper_trail_history/trackable_model.rb', line 48

def self.populate_count_cache(models_by_version_class, count_cache)
  models_by_version_class.each do |version_class, models_for_class|
    counts = fetch_version_counts(version_class, models_for_class)
    cache_counts_for_models(models_for_class, counts, count_cache)
  end
end

Instance Method Details

#human_nameObject



108
109
110
# File 'app/models/paper_trail_history/trackable_model.rb', line 108

def human_name
  klass.model_name.human(count: 2)
end

#item_type_for_versionsObject



83
84
85
86
87
# File 'app/models/paper_trail_history/trackable_model.rb', line 83

def item_type_for_versions
  # PaperTrail stores item_type as the class name, but let's be explicit
  # and handle potential namespace issues
  klass.name
end

#recent_versions(limit = 10) ⇒ Object



94
95
96
# File 'app/models/paper_trail_history/trackable_model.rb', line 94

def recent_versions(limit = 10)
  versions.order(created_at: :desc).limit(limit)
end

#total_versions_countObject



89
90
91
92
# File 'app/models/paper_trail_history/trackable_model.rb', line 89

def total_versions_count
  # Use cached count if available (from all_with_counts), otherwise query
  @cached_version_count || versions.count
end

#version_classObject



98
99
100
# File 'app/models/paper_trail_history/trackable_model.rb', line 98

def version_class
  @version_class ||= klass.paper_trail.version_class || PaperTrail::Version
end

#version_table_nameObject



102
103
104
# File 'app/models/paper_trail_history/trackable_model.rb', line 102

def version_table_name
  version_class.table_name
end

#versionsObject



79
80
81
# File 'app/models/paper_trail_history/trackable_model.rb', line 79

def versions
  version_class.where(item_type: item_type_for_versions)
end