Module: Kaching::CacheCounter

Included in:
ModelAdditions::ClassMethods
Defined in:
lib/kaching/cache_counter.rb,
lib/kaching/cache_counter_onmethod.rb

Instance Method Summary collapse

Instance Method Details

#cache_counter(attribute, options = {}) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/kaching/cache_counter.rb', line 3

def cache_counter(attribute, options = {})
  options = {}.merge(options || {})
    
  container_class = self
    
  count_method_name = options[:count_method_name] || "#{attribute.to_s}_count"
  reset_count_method_name = "reset_count_cache_#{attribute.to_s}!"
  
  Kaching.logger.info "DEFINE #{container_class.name}##{count_method_name}"
    
  container_class.send :define_method, count_method_name do
    value = Kaching.cache_store.fetch(kaching_key(attribute, :count)) {
      value = (block_given? ? yield(self) : self.send(attribute))
      value = value.count unless value.is_a?(Fixnum)
      
      Kaching.logger.info "FIRST FETCH #{value}"
      value
    }.to_i

    Kaching.logger.info "CALL #{container_class.name}##{count_method_name} = #{value}"

    value
  end
  
  container_class.send :define_method, reset_count_method_name do
    Kaching.cache_store.del(self.kaching_key(attribute, :count))
  end

  container_class.send(:after_commit) do
    if self.destroyed?
      Kaching.cache_store.del(self.kaching_key(attribute, :count))
    end
  end
    
  countable_class = options[:class_name].constantize if options[:class_name]
  countable_class ||= attribute.to_s.singularize.classify.constantize
    
  Kaching.logger.info "COUNTABLE DEFINE #{countable_class} after_commit"
    
  foreign_key = Kaching._extract_foreign_key_from(attribute, options, container_class)

  after_commit_method_name = "after_commit_#{count_method_name}"
  countable_class.send(:define_method, after_commit_method_name) do |action|
    begin
      Kaching.logger.info "COUNTABLE #{countable_class.name} after_commit foreign_key = #{foreign_key}"

      belongs_to_item = self.send(foreign_key)
    
      return unless belongs_to_item

      Kaching.logger.info " > COUNTABLE after_commit #{countable_class.name} belongs_to(#{foreign_key}) = #{belongs_to_item.class.name}##{belongs_to_item.id} | #{action.inspect}"
      
      counter_key = belongs_to_item.kaching_key(attribute, :count)
      
      if !Kaching.cache_store.exists(counter_key)
        belongs_to_item.send(count_method_name) # get fresh count from db
      else
        case action
        when :create
          Kaching.logger.info "  > COUNTABLE INCR #{counter_key}"
      
          Kaching.cache_store.incr(counter_key)
        when :destroy
          Kaching.logger.info "  > COUNTABLE DECR #{counter_key}"

          Kaching.cache_store.decr(counter_key)
        end
      end
    rescue
      puts $!.message
      puts $!.backtrace.join("\n")
      raise $!
    end
  end

  countable_class.send(:after_commit) do
    action = if self.send(:transaction_include_action?, :create)
      :create
    elsif self.destroyed?
      :destroy
    end

    self.send(after_commit_method_name, action) if action
  end
end