Last active
March 14, 2023 21:39
-
-
Save dalezak/086ccb6e4f2beb868c5bd0d5e9b9640a to your computer and use it in GitHub Desktop.
Rails Cacheable Concern
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Rails concern that tracks and purges cache keys to avoid using Rails.cache.delete_matched since its very costly on Redis. | |
# | |
# @countries = Country.query_cached('countries:index', "limit:#{@limit}", "offset:#{@offset}") do | |
# query.limit(@limit).offset(@offset).all.to_a | |
# end | |
module Cacheable | |
extend ActiveSupport::Concern | |
included do | |
before_save :purge_cache | |
before_destroy :purge_cache | |
end | |
class_methods do | |
def find_cached(id) | |
Rails.cache.fetch(find_cached_key(id), skip_nil: true) do | |
find(id) | |
end | |
end | |
def find_cached_key(id) | |
"#{model_name.cache_key}/#{id}/find_cached" | |
end | |
def query_cached(*keys, &block) | |
unless query_cached_keys.include?(query_cached_key(keys)) | |
query_cached_keys << query_cached_key(keys) | |
Rails.cache.write(query_cached_keys_key, query_cached_keys) | |
end | |
Rails.cache.fetch(query_cached_key(keys), skip_nil: true) do | |
block.call | |
end | |
end | |
def query_cached_key(*keys) | |
"#{model_name.cache_key}/query_cached/#{keys.join("/")}" | |
end | |
def query_cached_keys_key | |
"#{model_name.cache_key}/query_cached_keys" | |
end | |
def query_cached_keys | |
@query_cached_keys ||= Rails.cache.read(query_cached_keys_key, skip_nil: true) || [] | |
end | |
def purge_cache | |
find_each do |record| | |
record.purge_cache | |
end | |
end | |
end | |
def find_cached_key | |
@find_cached_key ||= self.class.find_cached_key(id) | |
end | |
def purge_cache | |
starting = Process.clock_gettime(Process::CLOCK_MONOTONIC) | |
Rails.cache.delete(self.class.find_cached_key(id)) | |
if self.class.query_cached_keys.present? | |
# TODO use Rails.cache.delete_multi after upgrading to Rails 6.1 | |
# Rails.cache.delete_multi(self.class.query_cached_keys) | |
self.class.query_cached_keys.each do |query_cached_key| | |
Rails.cache.delete(query_cached_key) | |
end | |
Rails.cache.delete(self.class.query_cached_keys_key) | |
Rails.cache.delete_match | |
end | |
ending = Process.clock_gettime(Process::CLOCK_MONOTONIC) | |
Rails.logger.debug "#{self.class.name}#purge_cache #{ending - starting} seconds" | |
return true | |
end | |
def query_cached(*keys, &block) | |
Rails.cache.fetch("#{self.cache_key_with_version}/#{keys.join("/")}") do | |
block.call | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment