module Cacheable::AssocationCache

Public Instance Methods

build_cache_belongs_to(association, association_name) click to toggle source

No expiring callback

# File lib/cacheable/types/association_cache.rb, line 42
def build_cache_belongs_to(association, association_name)
  polymorphic = association.options[:polymorphic]
  polymorphic ||= false

  method_name         = association_name
  cached_method_name = :"cached_#{association_name}"

  define_method(cached_method_name) do
    if instance_variable_get("@#{cached_method_name}").nil?
      cache_key = belong_association_cache_key(association_name, polymorphic)
      result = if cache_key
        association_cache.delete(association_name)
        Cacheable.fetch(cache_key) do
          send(association_name)
        end
      else
        # Should be nil, but preserve functionality
        send(association_name)
      end
      instance_variable_set("@#{cached_method_name}", result)
    end
    instance_variable_get("@#{cached_method_name}")
  end
end
build_cache_has_and_belongs_to_many(association, association_name) click to toggle source
# File lib/cacheable/types/association_cache.rb, line 102
def build_cache_has_and_belongs_to_many(association, association_name)
  # 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"

    define_method :"expire_#{association_name}_cache" do

      method_name = :"#{reverse_association.name}"
      cached_method_name = :"cached_#{reverse_association.name}"

      if respond_to? cached_method_name
        unless send(cached_method_name).nil?
          # cached_viewable.expire_association_cache
          send(cached_method_name).expire_association_cache(association_name)
        end
      elsif !send(method_name).nil?
        send(method_name).each do |assoc|
          next if assoc.nil?
          assoc.expire_association_cache(association_name)
        end
      end

    end
  end
end
build_cache_has_many(association, association_name) click to toggle source
# File lib/cacheable/types/association_cache.rb, line 132
def build_cache_has_many(association, association_name)
  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"

    define_method :"expire_#{association_name}_cache" do

      cached_method_name = :"cached_#{reverse_association.name}"
      method_name = :"#{reverse_association.name}"

      if respond_to? cached_method_name
        unless send(cached_method_name).nil?
          send(cached_method_name).expire_association_cache(association_name)
        end
      elsif !send(method_name).nil?
        send(method_name).expire_association_cache(association_name)
      end

    end
  end
end
build_cache_has_through(association, association_name, through_reflection_name) click to toggle source
# File lib/cacheable/types/association_cache.rb, line 67
def build_cache_has_through(association, association_name, through_reflection_name)
  through_association = self.reflect_on_association(through_reflection_name)

  reverse_through_association = through_association.klass.reflect_on_all_associations(:belongs_to).detect do |assoc|
    assoc.klass.ancestors.include?(Cacheable) && assoc.klass.reflect_on_association(association.name)
  end

  # 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"

      define_method(:"expire_#{association_name}_cache") do

        method_name = reverse_association.name
        cached_method_name = :"cached_#{reverse_association.name}"

        if respond_to? cached_method_name
          unless send(cached_method_name).nil?
            send(cached_method_name).expire_association_cache(association_name)
          end
        elsif !send(method_name).nil?
          if send(method_name).respond_to?(reverse_through_association.name) && !send(method_name).send(reverse_through_association.name).nil?
            send(method_name).send(reverse_through_association.name).expire_association_cache(association_name)
          end
        end

      end
    end
  end
end
with_association(*association_names) click to toggle source
# File lib/cacheable/types/association_cache.rb, line 4
def with_association(*association_names)
  self.cached_associations ||= []
  self.cached_associations += association_names

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

    if :belongs_to == association.macro
      build_cache_belongs_to(association, association_name)
    else

      if through_reflection_name = association.options[:through]
        build_cache_has_through(association, association_name, through_reflection_name)
      elsif :has_and_belongs_to_many == association.macro
        build_cache_has_and_belongs_to_many(association, association_name)
      else
        build_cache_has_many(association, association_name)
      end

      method_name = :"cached_#{association_name}"
      define_method(method_name) do
        if instance_variable_get("@#{method_name}").nil?
          association_cache.delete(association_name)
          cache_key = have_association_cache_key(association_name)
          result = Cacheable.fetch(cache_key) do
            send(association_name)
          end
          instance_variable_set("@#{method_name}", result)
        end
        instance_variable_get("@#{method_name}")
      end

    end

  end
end