Module: Cacheable::AssocationCache

Included in:
Caches
Defined in:
lib/cacheable/types/association_cache.rb

Instance Method Summary collapse

Instance Method Details

#with_association(*association_names) ⇒ Object



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
88
89
# File 'lib/cacheable/types/association_cache.rb', line 4

def with_association(*association_names)
  self.cached_associations = association_names

  association_names.each do |association_name|
    association = reflect_on_association(association_name)

    if :belongs_to == association.macro
      polymorphic = association.options[:polymorphic]
      polymorphic ||= false

      define_method("cached_#{association_name}") do
        Rails.cache.fetch belong_association_cache_key(association_name, polymorphic) do
          send(association_name)
        end
      end
    else
      if through_reflection_name = association.options[:through]
        through_association = self.reflect_on_association(through_reflection_name)

        # FIXME it should be the only reflection but I'm not 100% positive
        reverse_through_association = through_association.klass.reflect_on_all_associations(:belongs_to).first

        # In a through association it doesn't have to be a belongs_to
        reverse_association = association.klass.reflect_on_all_associations(:belongs_to).find { |reverse_association|
          reverse_association.options[:polymorphic] ? reverse_association.name == association.source_reflection.options[:as] : reverse_association.klass == self
        }
        if reverse_association
          association.klass.class_eval do
            after_commit "expire_#{association_name}_cache".to_sym

            define_method("expire_#{association_name}_cache") do
              if respond_to? "expire_#{reverse_association.name}_cache".to_sym
                # cached_viewable.expire_association_cache
                send("cached_#{reverse_association.name}").expire_association_cache(association_name)
              else
                send(reverse_association.name).send(reverse_through_association.name).expire_association_cache(association_name)
              end
            end
          end
        end
      elsif :has_and_belongs_to_many == association.macro
          # No such thing as a polymorphic has_and_belongs_to_many
          reverse_association = association.klass.reflect_on_all_associations(:has_and_belongs_to_many).find { |reverse_association|
            reverse_association.klass == self
          }

          association.klass.class_eval do
            after_commit "expire_#{association_name}_cache".to_sym

            define_method "expire_#{association_name}_cache" do
              if respond_to? "cached_#{reverse_association.name}".to_sym
                # cached_viewable.expire_association_cache
                send("cached_#{reverse_association.name}").expire_association_cache(association_name)
              else
                send("#{reverse_association.name}").each do |assoc|
                  assoc.expire_association_cache(association_name)
                end
              end
            end
          end
      else
        reverse_association = association.klass.reflect_on_all_associations(:belongs_to).find { |reverse_association|
          reverse_association.options[:polymorphic] ? reverse_association.name == association.options[:as] : reverse_association.klass == self
        }

        association.klass.class_eval do
          after_commit "expire_#{association_name}_cache".to_sym

          define_method "expire_#{association_name}_cache" do
            if respond_to? "cached_#{reverse_association.name}".to_sym
              send("cached_#{reverse_association.name}").expire_association_cache(association_name)
            else
              send("#{reverse_association.name}").expire_association_cache(association_name)
            end
          end
        end
      end

      define_method("cached_#{association_name}") do
        Rails.cache.fetch have_association_cache_key(association_name) do
          send(association_name).respond_to?(:to_a) ? send(association_name).to_a : send(association_name)
        end
      end
    end
  end
end