Module: LastModCache::ClassMethods

Defined in:
lib/last_mod_cache.rb

Overview

Class methods mixed into an ActiveRecord model that includes LastModCache.

Instance Method Summary collapse

Instance Method Details

#all_with_cache(options = {}, &block) ⇒ Object

Find all records that match a query and store it in the cache. The cache entry will be invalidated whenever the updated_at column is advanced on any record in the table.

The options parameter can contain any options allowed in the all method with the addition of a :cache option which can be used to pass options to the cache itself.



73
74
75
76
77
78
79
80
81
82
# File 'lib/last_mod_cache.rb', line 73

def all_with_cache(options = {}, &block)
  options = deep_clone(options)
  cache_options, options = extract_cache_options(options)
  block ||= lambda{ all(options) }
  Proxy.new do
    max_updated_at, count = max_updated_at_and_count
    records = last_mod_cache.fetch(updated_at_cache_key(:all_with_cache, options, max_updated_at, count), cache_options, &block)
    records.freeze
  end
end

#find_with_cache(id_or_ids, options = nil) ⇒ Object

Find a record by id or ids in database and store it in the cache. The cache entry will be invalidated whenever the updated_at column on that record is changed.

The options parameter can contain any options allowed in the first method with the addition of a :cache option which can be used to pass options to the cache



106
107
108
109
110
111
112
113
114
115
# File 'lib/last_mod_cache.rb', line 106

def find_with_cache(id_or_ids, options = nil)
  options = options ? deep_clone(options) : {}
  cache_options, options = extract_cache_options(options)
  finder = lambda{ options.blank? ? find(id_or_ids) : find(id_or_ids, options) }
  if id_or_ids.is_a?(Array)
    all_with_cache(options.merge(:conditions => {primary_key => id_or_ids}, :cache => cache_options), &finder)
  else
    first_with_cache(options.merge(:conditions => {primary_key => id_or_ids}, :cache => cache_options), &finder)
  end
end

#first_with_cache(options = {}, &block) ⇒ Object

Find the first that matches a query and store it in the cache. The cache entry will be invalidated whenever the updated_at column on that record is changed.

The options parameter can contain any options allowed in the first method with the addition of a :cache option which can be used to pass options to the cache itself.



89
90
91
92
93
94
95
96
97
98
99
# File 'lib/last_mod_cache.rb', line 89

def first_with_cache(options = {}, &block)
  options = deep_clone(options)
  cache_options, options = extract_cache_options(options)
  conditions = options.delete(:conditions)
  Proxy.new do
    id, timestamp = id_and_updated_at(:conditions => conditions)
    block ||= lambda{ all(options.merge(:limit => 1, :conditions => {primary_key => id})).first if id }
    record = last_mod_cache.fetch(updated_at_cache_key(:first_with_cache, options.merge(:conditions => conditions), timestamp), cache_options, &block)
    record.freeze if record
  end
end

#last_mod_cache_configObject

Get the cache configuration for the class.



118
119
120
121
122
123
124
# File 'lib/last_mod_cache.rb', line 118

def last_mod_cache_config
  if defined?(@last_mod_cache_config) && @last_mod_cache_config
    @last_mod_cache_config
  else
    superclass.last_mod_cache_config if superclass.respond_to?(:last_mod_cache_config)
  end
end

#max_updated_at_and_countObject

Get the maximum value in the updated at column and the count of all records in the database. This information can be used to generate self-expiring cache keys for models that change infrequently.



155
156
157
158
159
160
# File 'lib/last_mod_cache.rb', line 155

def max_updated_at_and_count
  result = connection.select_one("SELECT MAX(#{connection.quote_column_name(updated_at_column)}) AS #{connection.quote_column_name('updated_at')}, COUNT(*) AS #{connection.quote_column_name('row_size')} FROM #{connection.quote_table_name(table_name)}")
  updated_at = result['updated_at']
  updated_at = columns_hash[updated_at_column.to_s].type_cast(updated_at) if updated_at.is_a?(String)
  [updated_at, result['row_size'].to_i]
end

#method_missing_with_last_mod_cache(method, *args, &block) ⇒ Object

Hook into method_missing to add “_with_cache” as a suffix to dynamic finder methods.



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/last_mod_cache.rb', line 127

def method_missing_with_last_mod_cache(method, *args, &block) #:nodoc:
  match = method.to_s.match(DYNAMIC_FINDER_METHOD_PATTERN)
  if match
    finder_column_names = match[2].split("_and_")
    finder_values = args.dup
    options = finder_values.extract_options!
    
    unless finder_column_names.size == finder_values.size
      raise ArgumentError.new("wrong number of arguments (#{finder_values.size} for #{finder_column_names.size})")
    end
    
    unless (column_names & finder_column_names).size == finder_column_names.size
      raise NoMethodError.new("dynamic finder #{method} does not exist on #{name}")
    end
    
    conditions = {}
    finder_column_names.zip(finder_values).each do |col, val|
      conditions[col] = val
    end
    options = options.merge(:conditions => conditions)
    match[1] ? all_with_cache(options) : first_with_cache(options)
  else
    method_missing_without_last_mod_cache(method, *args, &block)
  end
end