Skip to content

Instantly share code, notes, and snippets.

@darrencauthon
Created September 19, 2014 19:28
Show Gist options
  • Save darrencauthon/1510f6de75a64c9b6d7c to your computer and use it in GitHub Desktop.
Save darrencauthon/1510f6de75a64c9b6d7c to your computer and use it in GitHub Desktop.
Surgical caching
module CachingLayer
class << self
def method_missing meth, *args, &block
action = meth.to_s.split('_')[0].to_sym
object_id = args[0].is_a?(ActiveRecord::Base) ? args[0].id : args[0]
object_type = meth.to_s.sub("#{action}_", '').to_sym
case action
when :find
block = -> { object_type.to_s.classify.constantize.where(id: object_id).first } if block.nil?
fetch_object object_type, object_id, &block
when :bust
bust_object object_type, object_id
end
end
end
def self.register_cached_item_and_fetch key, options = {}, &block
register_cached_item key, options, &block
fetch key
end
def self.register_cached_item key, options = {}, &block
@cached_items ||= {}
exists = @cached_items[key].present?
@cached_items[key] = { block: block, options: options }
if exists
if @cached_items[key][:options][:related_to_objects]
@cached_items[key][:options][:related_to_objects].each do |object_type|
tie_object_type_with_key object_type, key
end
end
else
bust key
end
end
def self.tie_object_type_with_key object_type, key
cache_keys_for(object_type) << key
end
def self.cache_keys_for object_type
@cache_busters ||= {}
@cache_busters[object_type] ||= []
end
def self.cache_key_for object_type, object_id
"fast_#{object_type}_#{object_id}"
end
def self.fetch_object object_type, object_id, &block
fetch(cache_key_for(object_type, object_id), &block)
end
def self.fetch key, &block
@cached_items ||= {}
block_to_run = if @cached_items[key]
@cached_items[key][:block]
else
block
end
enabled? ? Rails.cache.fetch(key, &block_to_run) : block_to_run.call
end
def self.bust_object object_type, object_id
bust cache_key_for(object_type, object_id)
cache_keys_for(object_type).each { |k| bust k }
end
def self.bust key
Rails.cache.delete key
end
def self.enabled?
true # ?
end
end
class ComplicatedController < ApplicationController
def list
#render json: a_buncha_complicated_processes
data = CachingLayer.register_cached_item_and_fetch('a buncha complicated processes', { related_to_objects: [:form] }) do
a_buncha_complicated_processes
end
render json: data
end
end
class Form < ActiveRecord::Base
after_save { |f| CachingLayer.bust_form f }
after_destroy { |f| CachingLayer.bust_form f }
def self.cached_find id
CachingLayer.find_form id
end
def self.cached_all
CachingLayer.register_cached_item_and_fetch('forms_all', { related_to_objects: [:form] }) { Form.all }
end
end
@darrencauthon
Copy link
Author

If I call

  Form.first.save

The processes and items tied to "form" will be invalidated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment