require 's3' class S3Cache < ActionController::Caching::Fragments::UnthreadedFileStore def initialize(bucket, cache_directory) @aws_access_key = 'YOURAWSACCESSKEY' # your AWS ACCESS KEY @aws_secret_access_key = 'YOURAWSSECRETKEY' # your SECRET @bucket = bucket @cache_path = cache_directory @conn = S3::AWSAuthConnection.new(@aws_access_key, @aws_secret_access_key) if ActionController::Base.allow_concurrency @mutex = Mutex.new FileStore.send(:include, ThreadSafety) end end def write(name, value, options = nil) #:nodoc: s3 = @conn.put(@bucket, real_file_path(name), value, { "x-amz-acl" => "public-read", "Content-Type" => "text/plain" } ) unless s3.http_response.message == "OK" ActionController::Base.logger.error "Couldn't create cache directory: #{name} (#{s3.http_response.message})" if ActionController::Base.logger end end def read(name, options = nil) #:nodoc: s3 = @conn.get(@bucket, real_file_path(name)) s3.http_response.message == "OK" ? s3.object.data : nil end def delete(name, options) #:nodoc: s3 = @conn.delete(@bucket, real_file_path(name)) unless s3.http_response.message == "No Content" ActionController::Base.logger.error "Couldn't delete file: #{name} (#{s3.http_response.message})" if ActionController::Base.logger end end def delete_matched(matcher, options) #:nodoc: @conn.list_bucket(@bucket).entries.map { |entry| entry.key }.each do |f| if f =~ matcher delete(f, nil) end end end end #add ability to cache xml files module ActionView module Helpers module CacheHelper def cache_xml(name = {}, &block) @controller.cache_xml_fragment(block, name) end end end end module ActionController module Caching module Fragments # Called by CacheHelper#cache_xml def cache_xml_fragment(block, name = {}, options = nil) unless perform_caching then block.call; return end if cache = read_fragment(name, options) cache else write_fragment(name, block.call, options) end end # The below is needed to alter the file name structure. If it is an xml or rss file written with # cache_xml_fragment, this will write the file name as a regular xml # file name (/posts.xml) rather than posts.part=xml.cache. class UnthreadedFileStore private def real_file_path(name) if name["part=xml"] '%s/%s' % [@cache_path, name.gsub('?', '.').gsub(':', '.').gsub('part=xml', 'xml')] else '%s/%s.cache' % [@cache_path, name.gsub('?', '.').gsub(':', '.')] end end end end end end