Skip to content

Instantly share code, notes, and snippets.

@andreimaxim
Forked from tispratik/override_cache_key.rb
Created February 13, 2022 08:50
Show Gist options
  • Save andreimaxim/41bfdc5e501fcd1d3870f02989dac9ce to your computer and use it in GitHub Desktop.
Save andreimaxim/41bfdc5e501fcd1d3870f02989dac9ce to your computer and use it in GitHub Desktop.
Override cache key and touch methods in active record when we cannot update the last modified / updated at column in database. We keep track of the changes in memcache.
module CacheKeyMonkeyPatch
module ActiveRecord
module Integration
# Returns a cache key that can be used to identify this record.
#
# ==== Examples
#
# Product.new.cache_key # => "products/new"
# Product.find(5).cache_key # => "products/5" (updated_at / last_modified_time not available)
# Person.find(5).cache_key # => "people/5-20140227181414671756000" (updated_at / last_modified_time available)
def cache_key
last_update_timestamp = Rails.cache.read(object_key)
return "#{self.class.model_name.cache_key}/#{id}-#{last_update_timestamp}" if last_update_timestamp
case
when new_record?
cached_cache_key = "#{self.class.model_name.cache_key}/new"
when timestamp = (self[:updated_at] || self.respond_to?(:last_modified_time) && self.last_modified_time)
timestamp = timestamp.to_s(:nsec)
Rails.logger.info "\e[33m READ: #{object_key} from nil to #{timestamp}"
Rails.cache.write(object_key, timestamp)
cached_cache_key = "#{self.class.model_name.cache_key}/#{id}-#{timestamp}"
else
cached_cache_key = "#{self.class.model_name.cache_key}/#{id}"
end
cached_cache_key
end
end
end
end
ActiveRecord::Base.class_eval do
include CacheKeyMonkeyPatch::ActiveRecord::Integration
end
module ActiveRecord
class Base
def update_cache_key_for_associated_belongs_to_models(event)
belongs_to_associations_to_touch = self.class.reflect_on_all_associations(:belongs_to).select { |assoc| assoc.options[:touch] }
belongs_to_associations_to_touch.each do |belongs_to_assoc|
associated_object = self.send(belongs_to_assoc.name)
associated_object.touch("PROPAGATE from #{self.class.to_s}") if associated_object
end
end
def touch(event = nil)
event ||= 'CREATE'
cached_timestamp = Rails.cache.fetch(object_key) || 'nil'
new_timestamp = Time.zone.now.to_s(:nsec)
Rails.logger.info "\e[33m #{event} #{object_key} from #{cached_timestamp} to #{new_timestamp}"
Rails.cache.write(object_key, new_timestamp)
update_cache_key_for_associated_belongs_to_models(event)
end
def object_key
"cache_key_#{self.class.model_name.i18n_key}_#{self.id}"
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment