module ManageCache::LocalInstanceMethods

Public Instance Methods

cache_key_for(spec, opts={}) click to toggle source
# File lib/manage_cache.rb, line 37
def cache_key_for(spec, opts={})
  instance_variable_get("@cache_key_for_#{spec}") ||
    instance_variable_set("@cache_key_for_#{spec}", prepare_cache_key(spec, opts))
end
dump_cache!() click to toggle source
# File lib/manage_cache.rb, line 24
def dump_cache!
  self.class.cache_keys_specs.each do |key_name, key_specs|
    if delete_cache?(key_specs)
      if !key_specs[:regexp].blank?
        delete_cache_w_regexp(key_name)
      else
        delete_cache(key_name)
      end
      instance_variable_set("@cache_key_for_#{key_name}", nil)
    end 
  end
end

Private Instance Methods

delete_cache(key_name) click to toggle source

the rails helper method 'cache (name, opts) do …' adds some extras to the cache key. To run with this gem, you have to add 'skip_digest: true'. Any other options will prevent correct cache deletion!!

# File lib/manage_cache.rb, line 144
def delete_cache(key_name)
  [cache_key_for(key_name), "views/#{cache_key_for(key_name)}"].each do |key|
    Rails.cache.delete(key)
  end
end
delete_cache?(key_specs) click to toggle source

if some attributes are specified in :if_changed check whether they changed and delete cache only if they changed

if not specified delete cache

# File lib/manage_cache.rb, line 156
def delete_cache?(key_specs)
  !key_specs[:if_changed] or 
    self.changed != (self.changed - key_specs[:if_changed].map(&:to_s))
end
delete_cache_w_regexp(key_name) click to toggle source

Opts added to cache_key_for will be suffixed to the rest of the cache_key. For these opts to take effect on cache management (e.g. deletion) use `regexp: { opts_key: “matcher_string” , .… } e.g.:

in the paginated index view:

<% cache @users.last.try(:cache_key_for, :users_index, page: params[:page]) do %>

in the model:

class User < ActiveRecord::Base
  manage_cache_for users_index: { 
                     class_eval: { max_up: "maximum(:updated_at)"} 
                     regexp:     { page: "\\d+" }
                   }

be aware, that the matcher_string has to be escaped (e.g. “\d+” instead of “d+”)!

# File lib/manage_cache.rb, line 127
def delete_cache_w_regexp(key_name)
  specs = self.class.cache_keys_specs[key_name]

  regexp = specs[:regexp].inject([]) do |m, (k,v)| 
    redis_store = Rails.cache.class.name == "ActiveSupport::Cache::RedisStore"
    m << "#{k}=#{redis_store ? '*' : v}" 
  end.join('-')

  key = prepare_cache_key(key_name)
  Rails.cache.delete_matched("#{Regexp.escape(key)}-#{regexp}")
end
prepare_cache_key(spec, opts={}) click to toggle source
# File lib/manage_cache.rb, line 44
def prepare_cache_key(spec, opts={})
  cache_key = {}

  key_specs = self.class.cache_keys_specs[spec]

  if key_specs.blank?
    raise "The specification for cache_key '#{spec}' is missing in manage_cache in #{self.class.name}."
  end

  # some extra specification like :show or :index_row
  # defaults to the spec-key
  #
  cache_key[:spec] = spec

  # named values from some method calls
  # the easiest case would be updated_at e.g.:
  #
  #   class User < ActiveRecord::Base
  #     manage_cache_for user_updated_at: { instance_eval: { user: :id, updated_at: :updated_at }
  #
  # a slightly more complicated one would be:
  # imagine following models:
  #   User: has_many :shoes
  #   Shoe: belongs_to :user
  #
  # so in the Shoe model there would be:
  #
  #   class Shoe < ActiveRecord::Base
  #     belongs_to :user
  #     manage_cache_for users_shoes: { instance_eval: { user: "user.id", last_updated_shoe: "user.shoes.maximum(:updated_at)" } }
  #
  # and this cache_key could be used somewhere where the user`s shoes are shown e.g. :show or :index
  #
  #  e.g.
  #  <% cache user.shoes.last.try(:cache_key_for, :users_shoes), skip_digest: true do %>
  #    ....
  #
  # it is enough to take one of the users` shoes for the cache_key here
  # because it will write the user`s id
  # and the last updated shoe into the cache_key
  #
  key_specs[:instance_eval].each do |name, cmd| 
    cache_key[name] = self.instance_eval(cmd.to_s)
  end if key_specs[:instance_eval]
  
  key_specs[:class_eval].each do |name, cmd| 
    cache_key[name] = self.class.class_eval(cmd.to_s)
  end if key_specs[:class_eval]


  # merge static values from manage_cache_for sth: { static: 'static' }
  #
  # and opts from cache_key_for, like:
  #   <% cache cache_key_for(:sth, page: params[:page]) %>
  #
  [key_specs[:static], opts].each do |hash|
    cache_key.reverse_merge!(hash) if hash
  end

  cache_key.inject([]){ |mem, (k,v)| mem << "#{k}=#{v}" }.join('-')
end