make action and fragment caching of rails 3.0.9 compatible with content_for
module ActionController | |
class Metal | |
attr_internal :cached_content_for | |
end | |
module Caching | |
module Actions | |
def _save_fragment(name, options) | |
return unless caching_allowed? | |
content = response_body | |
content = content.join if content.is_a?(Array) | |
content = cached_content_for.merge(:layout => content) if cached_content_for.is_a?(Hash) | |
write_fragment(name, content, options) | |
end | |
end | |
module Fragments | |
def write_fragment_with_content_to_cache(key, content, options = nil) | |
return_content = write_fragment_without_content_to_cache(key, content, options) | |
return_content.is_a?(Hash) && return_content.key?(:layout) ? return_content[:layout] : return_content | |
end | |
def read_fragment_with_content_to_cache(key, options = nil) | |
result = read_fragment_without_content_to_cache(key, options) | |
if result.is_a?(Hash) && result.key?(:layout) | |
result = result.dup if result.frozen? | |
fragment = result.delete(:layout) | |
self.cached_content_for = (self.cached_content_for || {}).merge(result){|_, v1, v2| v1 + v2 } | |
result = fragment | |
end | |
result.respond_to?(:html_safe) ? result.html_safe : result | |
end | |
alias_method_chain :write_fragment, :content_to_cache | |
alias_method_chain :read_fragment, :content_to_cache | |
end | |
end | |
end | |
module ActionView | |
module Rendering | |
# Added to support implementation of action caching | |
def _render_template_with_cached_content_for(template, layout = nil, options = {}) | |
if controller.respond_to?('caching_allowed?') && controller.caching_allowed? | |
if controller.cached_content_for.is_a?(Hash) | |
controller.cached_content_for.each { |k, v| content_for(k, v) } | |
controller.cached_content_for = {} | |
end | |
return_value = _render_template_without_cached_content_for(template, layout, options) | |
elsif | |
return_value = _render_template_without_cached_content_for(template, layout, options) | |
end | |
return_value | |
end | |
alias_method_chain :_render_template, :cached_content_for | |
end | |
module Helpers | |
module CaptureHelper | |
# Added to support implementation of fragment caching | |
def cache_with_content_for #:nodoc:# | |
@_subset_content_for ||= [] | |
@_subset_content_for.push(Hash.new { |h,k| h[k] = ActiveSupport::SafeBuffer.new }) | |
@cache_level = @_subset_content_for.size | |
yield | |
ensure | |
@_subset_content_for.pop | |
@cache_level = @_subset_content_for.size | |
end | |
def cache_level | |
@cache_level ||= 1 | |
@cache_level - 1 | |
end | |
# Added to support implementation of action caching | |
def content_to_cache #:nodoc:# | |
cache_this = (@_subset_content_for && @_subset_content_for[cache_level]) || @_content_for.except(:layout) | |
cache_this.dup.tap {|h| h.default = nil } | |
end | |
# Overwrite content_for to support fragment caching | |
def content_for(name, content = nil, &block) | |
content = capture(&block) if block_given? | |
@_content_for[name] << content if content | |
if content && @_subset_content_for && @_subset_content_for[cache_level] | |
@_subset_content_for[cache_level][name] << content | |
# также нужно передать этот контент всем родительским кеш-блокам | |
(cache_level - 1).downto(0) do |i| | |
@_subset_content_for[i][name] << content | |
end | |
end | |
@_content_for[name] unless content | |
end | |
end | |
module CacheHelper | |
def fragment_for(name = {}, options = nil, &block) #:nodoc: | |
if controller.fragment_exist?(name, options) | |
fragment = controller.read_fragment(name, options) | |
if controller.cached_content_for.is_a?(Hash) | |
controller.cached_content_for.each { |k, v| content_for(k, v) } | |
controller.cached_content_for = {} | |
end | |
fragment | |
else | |
pos = output_buffer.length | |
hash_to_cache = nil | |
cache_with_content_for do | |
yield | |
if output_buffer.is_a?(ActionView::OutputBuffer) | |
safe_output_buffer = output_buffer.to_str | |
fragment = safe_output_buffer.slice!(pos..-1) | |
self.output_buffer = ActionView::OutputBuffer.new(safe_output_buffer) | |
else | |
fragment = output_buffer.slice!(pos..-1) | |
end | |
hash_to_cache = {:layout => fragment}.merge(content_to_cache) | |
end | |
controller.write_fragment(name, hash_to_cache, options) | |
end | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment