Created
December 28, 2011 04:20
-
-
Save gazay/1526231 to your computer and use it in GitHub Desktop.
Creating Fragment class for controller caching
This file contains hidden or 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
# rails/actionpack/lib/action_view/cache_helper.rb | |
private | |
# TODO: Create an object that has caching read/write on it | |
def fragment_for(name = {}, options = nil, &block) #:nodoc: | |
if fragment = controller.find_fragment(name, options) | |
fragment.read | |
else | |
# VIEW TODO: Make #capture usable outside of ERB | |
# This dance is needed because Builder can't use capture | |
pos = output_buffer.length | |
yield | |
output_safe = output_buffer.html_safe? | |
content = output_buffer.slice!(pos..-1) | |
if output_safe | |
self.output_buffer = output_buffer.class.new(output_buffer) | |
end | |
if fragment = controller.create_fragment(name, content, options) | |
fragment.write | |
end | |
end | |
end |
This file contains hidden or 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
# rails/actionpack/lib/action_controller/caching/fragments.rb | |
module Fragments | |
# Given a key (as described in <tt>expire_fragment</tt>), returns | |
# a key suitable for use in reading, writing, or expiring a | |
# cached fragment. If the key is a hash, the generated key is the | |
# return value of url_for on that hash (without the protocol). | |
# All keys are prefixed with <tt>views/</tt> and uses | |
# ActiveSupport::Cache.expand_cache_key for the expansion. | |
def fragment_cache_key(key) | |
ActiveSupport::Cache.expand_cache_key(key.is_a?(Hash) ? url_for(key).split("://").last : key, :views) | |
end | |
# Find fragment from the location signified by | |
# <tt>key</tt> and creates new Fragment object | |
# (or find object in controller.fragments) | |
def find_fragment(key, options = nil) | |
return unless cache_configured? | |
# If we can keep fragment objects in controller instance | |
# here will be something like that: | |
# return self.fragments[key] if self.fragments[key] | |
if fragment_exist?(key, options) | |
key = fragment_cache_key(key) | |
ActionController::Caching::Fragment.new(key, options) | |
end | |
end | |
# Check if a cached fragment from the location signified by | |
# <tt>key</tt> exists (see <tt>expire_fragment</tt> for acceptable formats) | |
def fragment_exist?(key, options = nil) | |
return unless cache_configured? | |
key = fragment_cache_key(key) | |
instrument_fragment_cache :exist_fragment?, key do | |
cache_store.exist?(key, options) | |
end | |
end | |
# Create new Fragment object | |
# (and add it to controller.fragments) | |
def create_fragment(key, content, options = nil) | |
return unless cache_configured? | |
content = content.to_str | |
fragmented_key = fragment_cache_key(key) | |
ActionController::Caching::Fragment.new(fragmented_key, options, content) | |
# And if we can keep it in controller: | |
# self.fragments[key] = fragment | |
end | |
# Removes fragments from the cache. | |
# | |
# +key+ can take one of three forms: | |
# | |
# * String - This would normally take the form of a path, like | |
# <tt>pages/45/notes</tt>. | |
# * Hash - Treated as an implicit call to +url_for+, like | |
# <tt>{:controller => "pages", :action => "notes", :id => 45}</tt> | |
# * Regexp - Will remove any fragment that matches, so | |
# <tt>%r{pages/\d*/notes}</tt> might remove all notes. Make sure you | |
# don't use anchors in the regex (<tt>^</tt> or <tt>$</tt>) because | |
# the actual filename matched looks like | |
# <tt>./cache/filename/path.cache</tt>. Note: Regexp expiration is | |
# only supported on caches that can iterate over all keys (unlike | |
# memcached). | |
# | |
# +options+ is passed through to the cache store's <tt>delete</tt> | |
# method (or <tt>delete_matched</tt>, for Regexp keys.) | |
def expire_fragment(key, options = nil) | |
return unless cache_configured? | |
key = fragment_cache_key(key) unless key.is_a?(Regexp) | |
message = nil | |
instrument_fragment_cache :expire_fragment, key do | |
if key.is_a?(Regexp) | |
cache_store.delete_matched(key, options) | |
else | |
cache_store.delete(key, options) | |
end | |
end | |
end | |
end | |
class Fragment | |
# Fragment class using for working with cache entries | |
attr_reader :key, :options, :content | |
def initialize(key, options = nil, content = nil) | |
@key = key | |
@options = options | |
@content = content | |
end | |
# Reads a cached fragment from the location signified by <tt>key</tt> | |
def read | |
if content | |
content | |
else | |
instrument_fragment_cache :read_fragment, key do | |
result = cache_store.read(key, options) | |
@content = result.respond_to?(:html_safe) ? result.html_safe : result | |
end | |
end | |
end | |
# Writes <tt>content</tt> of the current Fragment object | |
# to the location signified by <tt>key</tt> | |
def write | |
instrument_fragment_cache :write_fragment, key do | |
cache_store.write(key, content, options) | |
end | |
content | |
end | |
# Expires current Fragment object | |
def expire | |
instrument_fragment_cache :expire_fragment, key do | |
cache_store.delete(key, options) | |
end | |
end | |
def instrument_fragment_cache(name, key) | |
ActiveSupport::Notifications.instrument("#{name}.action_controller", :key => key){ yield } | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment