-
-
Save fastjames/2725983 to your computer and use it in GitHub Desktop.
Patch to get content_for working with action caching and fragment caching in Rails 3.1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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[:layout] : return_content | |
return content unless cache_configured? | |
key = fragment_cache_key(key) | |
instrument_fragment_cache :write_fragment, key do | |
cache_store.write(key, content, options) | |
end | |
content.is_a?(Hash) ? content[:layout] : 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 = result.dup if result.frozen? | |
fragment = result.delete(:layout) | |
self.cached_content_for = {}.merge(result)#(self.cached_content_for || {}).merge(result) | |
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 | |
class TemplateRenderer < AbstractRenderer | |
# Added to support implementation of action caching | |
def render_template_with_cached_content_for(template, layout_name = nil, locals = {}) | |
controller = @view.controller | |
if controller.respond_to?('caching_allowed?') && controller.caching_allowed? && controller.is_a?(ApplicationController) | |
controller.cached_content_for.each { |k, v| @view.content_for(k, v) unless @view.content_for?(k) } if controller.cached_content_for.is_a?(Hash) | |
return_value = render_template_without_cached_content_for(template, layout_name, locals) | |
controller.cached_content_for = @view.content_to_cache | |
elsif | |
return_value = render_template_without_cached_content_for(template, layout_name, locals) | |
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:# | |
@_content_for_to_cache = Hash.new { |h,k| h[k] = ActiveSupport::SafeBuffer.new } | |
yield | |
ensure | |
@_content_for_to_cache = Hash.new | |
end | |
# Added to support implementation of action caching | |
def content_to_cache #:nodoc:# | |
cache_this = @_content_for_to_cache || @view_flow.content.except(:layout) | |
# cache_this = @view_flow.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? | |
if content | |
if @_content_for_to_cache | |
@_content_for_to_cache[name] ||= Array.new | |
@_content_for_to_cache[name] << content | |
end | |
@view_flow.append(name, content) | |
nil | |
else | |
@view_flow.get(name) | |
end | |
end | |
end | |
module CacheHelper | |
def fragment_for(name = {}, options = nil, &block) #:nodoc: | |
if fragment = controller.read_fragment(name, options) | |
controller.cached_content_for.each { |k, v| content_for(k, v) } if controller.cached_content_for.is_a?(Hash) | |
fragment | |
else | |
pos = output_buffer.length | |
hash_to_cache = nil | |
cache_with_content_for do | |
yield | |
output_safe = output_buffer.html_safe? | |
fragment = output_buffer.slice!(pos..-1) | |
if output_safe | |
self.output_buffer = output_buffer.class.new(output_buffer) | |
end | |
hash_to_cache = {:layout => fragment}.merge(@_content_for_to_cache) | |
end | |
controller.write_fragment(name, hash_to_cache, options) | |
end | |
end | |
end | |
end | |
end |
Has anyone extracted this to a gem or submitted a PR to Rails core? We still need this for current versions of Rails!
I've submitted a pull request here, in case you're interested: rails/rails#39600
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi there! Have you tested the above code? If so, how to implement it (i.e. where to add the module)?