diff --git a/lib/chili_project/liquid/liquid_ext/block.rb b/lib/chili_project/liquid/liquid_ext/block.rb index 5c54c5f3..cf0b693e 100644 --- a/lib/chili_project/liquid/liquid_ext/block.rb +++ b/lib/chili_project/liquid/liquid_ext/block.rb @@ -19,15 +19,19 @@ module ChiliProject def self.included(base) base.send(:include, InstanceMethods) base.class_eval do - alias_method_chain :render_all, :cleaned_whitespace + alias_method_chain :render_all, :cleaned_whitespace_and_cache end end module InstanceMethods - def render_all_with_cleaned_whitespace(list, context) + def render_all_with_cleaned_whitespace_and_cache(list, context) # Remove the leading newline in a block's content list[0].sub!(/\A\r?\n/, "") if list[0].is_a?(String) - render_all_without_cleaned_whitespace(list, context) + + # prevent caching if there are any potentially active elements + context.not_cachable! if list.any? { |token| token.respond_to?(:render) } + + render_all_without_cleaned_whitespace_and_cache(list, context) end end end diff --git a/lib/chili_project/liquid/liquid_ext/context.rb b/lib/chili_project/liquid/liquid_ext/context.rb index 54f19604..d5123cac 100644 --- a/lib/chili_project/liquid/liquid_ext/context.rb +++ b/lib/chili_project/liquid/liquid_ext/context.rb @@ -47,6 +47,14 @@ module ChiliProject def html_results registers[:html_results] ||= {} end + + def cacheable? + registers.has_key?(:cachable) ? !!registers[:cachable] : true + end + + def not_cachable! + registers[:cachable] = false + end end end end diff --git a/lib/chili_project/liquid/template.rb b/lib/chili_project/liquid/template.rb index ab59cc45..2c2fd2eb 100644 --- a/lib/chili_project/liquid/template.rb +++ b/lib/chili_project/liquid/template.rb @@ -74,6 +74,26 @@ module ChiliProject context = context_from_render_options(*args) context.registers[:html_results] ||= {} + obj = context.registers[:object] + attribute = context.registers[:attribute] + + if Setting.cache_formatted_text? && cache_key = cache_key_for(Setting.text_formatting, obj, attribute) + # Text retrieved from the cache store may be frozen + # We need to dup it so we can do in-place substitutions with gsub! + result = Rails.cache.fetch(cache_key) + result ||= begin + result = render_context(context) + Rails.cache.write(cache_key, result) if context.cacheable? + result + end.dup + else + render_context(context) + end + end + + def render_context(context) + return '' if @root.nil? + # ENTER THE RENDERING STAGE # 1. Render the input as Liquid @@ -88,8 +108,8 @@ module ChiliProject # 2. Perform the Wiki markup transformation (e.g. Textile) obj = context.registers[:object] - attr = context.registers[:attribute] - result = Redmine::WikiFormatting.to_html(Setting.text_formatting, result, :object => obj, :attribute => attr) + attribute = context.registers[:attribute] + result = Redmine::WikiFormatting.to_html(Setting.text_formatting, result, :object => obj, :attribute => attribute) # 3. Now finally, replace the captured raw HTML bits in the final content length = nil @@ -105,6 +125,13 @@ module ChiliProject result end + + private + def cache_key_for(format, object, attribute) + if object && attribute && !object.new_record? && object.respond_to?(:updated_on) && !format.blank? + "formatted_text/#{format}/#{object.class.model_name.cache_key}/#{object.id}-#{attribute}-#{object.updated_on.to_s(:number)}" + end + end end end end diff --git a/lib/redmine/wiki_formatting.rb b/lib/redmine/wiki_formatting.rb index a3176b72..7a78fbcb 100644 --- a/lib/redmine/wiki_formatting.rb +++ b/lib/redmine/wiki_formatting.rb @@ -41,27 +41,7 @@ module Redmine end def to_html(format, text, options = {}, &block) - if Setting.cache_formatted_text? && text.size > 2.kilobyte && cache_store && cache_key = cache_key_for(format, options[:object], options[:attribute]) - # Text retrieved from the cache store may be frozen - # We need to dup it so we can do in-place substitutions with gsub! - cache_store.fetch cache_key do - formatter_for(format).new(text).to_html - end.dup - else - formatter_for(format).new(text).to_html - end - end - - # Returns a cache key for the given text +format+, +object+ and +attribute+ or nil if no caching should be done - def cache_key_for(format, object, attribute) - if object && attribute && !object.new_record? && object.respond_to?(:updated_on) && !format.blank? - "formatted_text/#{format}/#{object.class.model_name.cache_key}/#{object.id}-#{attribute}-#{object.updated_on.to_s(:number)}" - end - end - - # Returns the cache store used to cache HTML output - def cache_store - ActionController::Base.cache_store + formatter_for(format).new(text).to_html end end end