# -*- encoding : utf-8 -*- # A card that includes Abstract::SolidCache caches its core view # in a '+*solid cache' card. # If that card exists the core view returns its content as rendered view. # If it doesn't exist the usual core view is rendered and saved in that card. # # The cache expiration can be controlled with the cache_update_trigger and # cache_expire_trigger methods. card_accessor :solid_cache, type: :html def self.included host_class host_class.format(host_class.try(:cached_format) || :base) do view :core do |args| return super() unless args[:solid_cache] card.update_solid_cache if card.solid_cache_card.new? subformat(card.solid_cache_card)._render_core end end end format do def default_core_args args args[:solid_cache] = true unless args.key?(:solid_cache) end end module ClassMethods # If a card of the set given by 'set_of_changed_card' is changed # the given block is executed. It is supposed to return an array of # cards whose solid caches are expired because of the change. # @param set_of_changed_card [set constant] a set of cards that triggers # a cache update # @param args [Hash] # @option args [Symbol, Array] :on the action(s) # (:create, :update, or :delete) on which the cache update # should be triggered. Default is all actions. # @option args [Stage] :in_stage the stage when the update is executed. # Default is :integrate # @yield return a card or an array of cards with solid cache that need to be # updated def cache_update_trigger set_of_changed_card, args={}, &block define_event_to_update_expired_cached_cards( set_of_changed_card, args, :update_solid_cache, &block ) end # Same as 'cache_update_trigger' but expires instead of updates the # outdated solid caches def cache_expire_trigger set_of_changed_card, args={}, &block define_event_to_update_expired_cached_cards( set_of_changed_card, args, :expire_solid_cache, &block ) end def define_event_to_update_expired_cached_cards set_of_changed_card, args, method_name args[:on] ||= [:create, :update, :delete] name = event_name set_of_changed_card, args stage = args[:in_stage] || :integrate Card::Set.register_set set_of_changed_card set_of_changed_card.event name, stage, args do Array.wrap(yield(self)).compact.each do |expired_cache_card| next unless expired_cache_card.solid_cache? expired_cache_card.send method_name, self end end end def event_name set, args changed_card_set = set.shortname.tr(":", "_").underscore solid_cache_set = shortname.tr(":", "_").underscore + "__solid_cache" actions = Array.wrap(args[:on]).join("_") ["update", solid_cache_set, "changed_by", changed_card_set, "on", actions].join("___").to_sym end end def expire_solid_cache _changed_card=nil return unless solid_cache? Auth.as_bot do solid_cache_card.delete! end end def update_solid_cache changed_card=nil return unless solid_cache? new_content = if solid_cache_card.new? generate_content_for_cache changed_card else updated_content_for_cache changed_card end return unless new_content write_to_solid_cache new_content new_content end def generate_content_for_cache changed_card=nil format_type = try(:cached_format) || :base format(format_type)._render_core solid_cache: false, changed_card: changed_card end def updated_content_for_cache _changed_card=nil generate_content_for_cache end def write_to_solid_cache new_content Auth.as_bot do if solid_cache_card.new_card? solid_cache_card.update_attributes! content: new_content elsif new_content != solid_cache_card.content solid_cache_card.update_column :db_content, new_content solid_cache_card.expire end end end