Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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
You can’t perform that action at this time.