actionpack-action_caching-1.2.2/ 0000755 0000041 0000041 00000000000 14053115675 016616 5 ustar www-data www-data actionpack-action_caching-1.2.2/test/ 0000755 0000041 0000041 00000000000 14053115675 017575 5 ustar www-data www-data actionpack-action_caching-1.2.2/test/fixtures/ 0000755 0000041 0000041 00000000000 14053115675 021446 5 ustar www-data www-data actionpack-action_caching-1.2.2/test/fixtures/layouts/ 0000755 0000041 0000041 00000000000 14053115675 023146 5 ustar www-data www-data actionpack-action_caching-1.2.2/test/fixtures/layouts/talk_from_action.html.erb 0000644 0000041 0000041 00000000063 14053115675 030115 0 ustar www-data www-data
<%= params[:title] %>
<%= yield -%>
actionpack-action_caching-1.2.2/test/abstract_unit.rb 0000644 0000041 0000041 00000000445 14053115675 022767 0 ustar www-data www-data require "bundler/setup"
require "minitest/autorun"
require "action_controller"
require "active_record"
require "action_controller/action_caching"
FIXTURE_LOAD_PATH = File.expand_path("../fixtures", __FILE__)
if ActiveSupport.respond_to?(:test_order)
ActiveSupport.test_order = :random
end
actionpack-action_caching-1.2.2/test/caching_test.rb 0000644 0000041 0000041 00000064163 14053115675 022567 0 ustar www-data www-data require "abstract_unit"
require "mocha/setup"
CACHE_DIR = "test_cache"
# Don't change "../tmp" cavalierly or you might hose something you don't want hosed
TEST_TMP_DIR = File.expand_path("../tmp", __FILE__)
FILE_STORE_PATH = File.join(TEST_TMP_DIR, CACHE_DIR)
class CachingController < ActionController::Base
abstract!
self.cache_store = :file_store, FILE_STORE_PATH
end
class CachePath
def call(controller)
["controller", controller.params[:id]].compact.join("-")
end
end
class ActionCachingTestController < CachingController
rescue_from(Exception) { head 500 }
rescue_from(ActionController::UnknownFormat) { head :not_acceptable }
if defined? ActiveRecord
rescue_from(ActiveRecord::RecordNotFound) { head :not_found }
end
self.view_paths = FIXTURE_LOAD_PATH
before_action only: :with_symbol_format do
request.params[:format] = :json
end
caches_action :index, :redirected, :forbidden, if: ->(c) { c.request.format && !c.request.format.json? }, expires_in: 1.hour
caches_action :show, cache_path: "http://test.host/custom/show"
caches_action :edit, cache_path: ->(c) { c.params[:id] ? "http://test.host/#{c.params[:id]};edit" : "http://test.host/edit" }
caches_action :custom_cache_path, cache_path: CachePath.new
caches_action :symbol_cache_path, cache_path: :cache_path_protected_method
caches_action :with_layout
caches_action :with_format_and_http_param, cache_path: ->(c) { { key: "value" } }
caches_action :with_symbol_format, cache_path: "http://test.host/action_caching_test/with_symbol_format"
caches_action :not_url_cache_path, cache_path: ->(c) { "#{c.params[:action]}_key" }
caches_action :not_url_cache_path_no_args, cache_path: -> { "#{params[:action]}_key" }
caches_action :layout_false, layout: false
caches_action :with_layout_proc_param, layout: ->(c) { c.params[:layout] != "false" }
caches_action :with_layout_proc_param_no_args, layout: -> { params[:layout] != "false" }
caches_action :record_not_found, :four_oh_four, :simple_runtime_error
caches_action :streaming
caches_action :invalid
caches_action :accept
layout "talk_from_action"
def index
@cache_this = CacheContent.to_s
render plain: @cache_this
end
def redirected
redirect_to action: "index"
end
def forbidden
render plain: "Forbidden"
response.status = "403 Forbidden"
end
def with_layout
@cache_this = CacheContent.to_s
render html: @cache_this, layout: true
end
def with_format_and_http_param
@cache_this = CacheContent.to_s
render plain: @cache_this
end
def with_symbol_format
@cache_this = CacheContent.to_s
render json: { timestamp: @cache_this }
end
def not_url_cache_path
render plain: "cache_this"
end
alias_method :not_url_cache_path_no_args, :not_url_cache_path
def record_not_found
raise ActiveRecord::RecordNotFound, "oops!"
end
def four_oh_four
render plain: "404'd!", status: 404
end
def simple_runtime_error
raise "oops!"
end
alias_method :show, :index
alias_method :edit, :index
alias_method :destroy, :index
alias_method :custom_cache_path, :index
alias_method :symbol_cache_path, :index
alias_method :layout_false, :with_layout
alias_method :with_layout_proc_param, :with_layout
alias_method :with_layout_proc_param_no_args, :with_layout
def expire
expire_action controller: "action_caching_test", action: "index"
head :ok
end
def expire_xml
expire_action controller: "action_caching_test", action: "index", format: "xml"
head :ok
end
def expire_with_url_string
expire_action url_for(controller: "action_caching_test", action: "index")
head :ok
end
def streaming
render plain: "streaming", stream: true
end
def invalid
@cache_this = CacheContent.to_s
respond_to do |format|
format.json { render json: @cache_this }
end
end
def accept
@cache_this = CacheContent.to_s
respond_to do |format|
format.html { render html: @cache_this }
format.json { render json: @cache_this }
end
end
def expire_accept
if params.key?(:format)
expire_action action: "accept", format: params[:format]
elsif !request.format.html?
expire_action action: "accept", format: request.format.to_sym
else
expire_action action: "accept"
end
head :ok
end
protected
def cache_path_protected_method
["controller", params[:id]].compact.join("-")
end
if ActionPack::VERSION::STRING < "4.1"
def render(options)
if options.key?(:plain)
super({ text: options.delete(:plain) }.merge(options))
response.content_type = "text/plain"
elsif options.key?(:html)
super({ text: options.delete(:html) }.merge(options))
response.content_type = "text/html"
else
super
end
end
end
end
class CacheContent
def self.to_s
# Let Time spicy to assure that Time.now != Time.now
time = Time.now.to_f + rand
(time.to_s + "").html_safe
end
end
class ActionCachingMockController
attr_accessor :mock_url_for
attr_accessor :mock_path
def initialize
yield self if block_given?
end
def url_for(*args)
@mock_url_for
end
def params
request.parameters
end
def request
Object.new.instance_eval <<-EVAL
def path; "#{@mock_path}" end
def format; "all" end
def parameters; { format: nil }; end
self
EVAL
end
end
class ActionCacheTest < ActionController::TestCase
tests ActionCachingTestController
def setup
super
@routes = ActionDispatch::Routing::RouteSet.new
@request.host = "hostname.com"
FileUtils.mkdir_p(FILE_STORE_PATH)
@path_class = ActionController::Caching::Actions::ActionCachePath
@mock_controller = ActionCachingMockController.new
end
def teardown
super
FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
end
def test_simple_action_cache_with_http_head
draw do
get "/action_caching_test", to: "action_caching_test#index"
end
head :index
assert_response :success
cached_time = content_to_cache
assert_equal cached_time, @response.body
assert fragment_exist?("hostname.com/action_caching_test")
head :index
assert_response :success
assert_equal cached_time, @response.body
end
def test_simple_action_cache
draw do
get "/action_caching_test", to: "action_caching_test#index"
end
get :index
assert_response :success
cached_time = content_to_cache
assert_equal cached_time, @response.body
assert fragment_exist?("hostname.com/action_caching_test")
get :index
assert_response :success
assert_equal cached_time, @response.body
end
def test_simple_action_not_cached
draw do
get "/action_caching_test/destroy", to: "action_caching_test#destroy"
end
get :destroy
assert_response :success
cached_time = content_to_cache
assert_equal cached_time, @response.body
assert !fragment_exist?("hostname.com/action_caching_test/destroy")
get :destroy
assert_response :success
assert_not_equal cached_time, @response.body
end
def test_action_cache_with_layout
draw do
get "/action_caching_test/with_layout", to: "action_caching_test#with_layout"
end
get :with_layout
assert_response :success
cached_time = content_to_cache
assert_not_equal cached_time, @response.body
assert fragment_exist?("hostname.com/action_caching_test/with_layout")
get :with_layout
assert_response :success
assert_not_equal cached_time, @response.body
assert_equal @response.body, read_fragment("hostname.com/action_caching_test/with_layout")
end
def test_action_cache_with_layout_and_layout_cache_false
draw do
get "/action_caching_test/layout_false", to: "action_caching_test#layout_false"
end
get :layout_false, params: { title: "Request 1" }
assert_response :success
cached_time = content_to_cache
assert_equal "Request 1\n#{cached_time}", @response.body
assert_equal cached_time, read_fragment("hostname.com/action_caching_test/layout_false")
get :layout_false, params: { title: "Request 2" }
assert_response :success
assert_equal "Request 2\n#{cached_time}", @response.body
assert_equal cached_time, read_fragment("hostname.com/action_caching_test/layout_false")
end
def test_action_cache_with_layout_and_layout_cache_false_via_proc
draw do
get "/action_caching_test/with_layout_proc_param", to: "action_caching_test#with_layout_proc_param"
end
get :with_layout_proc_param, params: { title: "Request 1", layout: "false" }
assert_response :success
cached_time = content_to_cache
assert_equal "Request 1\n#{cached_time}", @response.body
assert_equal cached_time, read_fragment("hostname.com/action_caching_test/with_layout_proc_param")
get :with_layout_proc_param, params: { title: "Request 2", layout: "false" }
assert_response :success
assert_equal "Request 2\n#{cached_time}", @response.body
assert_equal cached_time, read_fragment("hostname.com/action_caching_test/with_layout_proc_param")
end
def test_action_cache_with_layout_and_layout_cache_true_via_proc
draw do
get "/action_caching_test/with_layout_proc_param", to: "action_caching_test#with_layout_proc_param"
end
get :with_layout_proc_param, params: { title: "Request 1", layout: "true" }
assert_response :success
cached_time = content_to_cache
assert_equal "Request 1\n#{cached_time}", @response.body
assert_equal "Request 1\n#{cached_time}", read_fragment("hostname.com/action_caching_test/with_layout_proc_param")
get :with_layout_proc_param, params: { title: "Request 2", layout: "true" }
assert_response :success
assert_equal "Request 1\n#{cached_time}", @response.body
assert_equal "Request 1\n#{cached_time}", read_fragment("hostname.com/action_caching_test/with_layout_proc_param")
end
def test_action_cache_conditional_options
draw do
get "/action_caching_test", to: "action_caching_test#index"
end
@request.accept = "application/json"
get :index
assert_response :success
assert !fragment_exist?("hostname.com/action_caching_test")
end
def test_action_cache_with_format_and_http_param
draw do
get "/action_caching_test/with_format_and_http_param", to: "action_caching_test#with_format_and_http_param"
end
get :with_format_and_http_param, format: "json"
assert_response :success
assert !fragment_exist?("hostname.com/action_caching_test/with_format_and_http_param.json?key=value.json")
assert fragment_exist?("hostname.com/action_caching_test/with_format_and_http_param.json?key=value")
end
def test_action_cache_with_symbol_format
draw do
get "/action_caching_test/with_symbol_format", to: "action_caching_test#with_symbol_format"
end
get :with_symbol_format
assert_response :success
assert !fragment_exist?("test.host/action_caching_test/with_symbol_format")
assert fragment_exist?("test.host/action_caching_test/with_symbol_format.json")
end
def test_action_cache_not_url_cache_path
draw do
get "/action_caching_test/not_url_cache_path", to: "action_caching_test#not_url_cache_path"
end
get :not_url_cache_path
assert_response :success
assert !fragment_exist?("test.host/action_caching_test/not_url_cache_path")
assert fragment_exist?("not_url_cache_path_key")
end
def test_action_cache_with_store_options
draw do
get "/action_caching_test", to: "action_caching_test#index"
end
CacheContent.expects(:to_s).returns('12345.0').once
@controller.expects(:read_fragment).with("hostname.com/action_caching_test", expires_in: 1.hour).once
@controller.expects(:write_fragment).with("hostname.com/action_caching_test", "12345.0", expires_in: 1.hour).once
get :index
assert_response :success
end
def test_action_cache_with_custom_cache_path
draw do
get "/action_caching_test/show", to: "action_caching_test#show"
end
get :show
assert_response :success
cached_time = content_to_cache
assert_equal cached_time, @response.body
assert fragment_exist?("test.host/custom/show")
get :show
assert_response :success
assert_equal cached_time, @response.body
end
def test_action_cache_with_custom_cache_path_in_block
draw do
get "/action_caching_test/edit(/:id)", to: "action_caching_test#edit"
end
get :edit
assert_response :success
assert fragment_exist?("test.host/edit")
get :edit, params: { id: 1 }
assert_response :success
assert fragment_exist?("test.host/1;edit")
end
def test_action_cache_with_custom_cache_path_with_custom_object
draw do
get "/action_caching_test/custom_cache_path(/:id)", to: "action_caching_test#custom_cache_path"
end
get :custom_cache_path
assert_response :success
assert fragment_exist?("controller")
get :custom_cache_path, params: { id: 1 }
assert_response :success
assert fragment_exist?("controller-1")
end
def test_action_cache_with_symbol_cache_path
draw do
get "/action_caching_test/symbol_cache_path(/:id)", to: "action_caching_test#symbol_cache_path"
end
get :symbol_cache_path
assert_response :success
assert fragment_exist?("controller")
get :symbol_cache_path, params: { id: 1 }
assert_response :success
assert fragment_exist?("controller-1")
end
def test_cache_expiration
draw do
get "/action_caching_test", to: "action_caching_test#index"
get "/action_caching_test/expire", to: "action_caching_test#expire"
end
get :index
assert_response :success
cached_time = content_to_cache
get :index
assert_response :success
assert_equal cached_time, @response.body
get :expire
assert_response :success
get :index
assert_response :success
new_cached_time = content_to_cache
assert_not_equal cached_time, @response.body
get :index
assert_response :success
assert_equal new_cached_time, @response.body
end
def test_cache_expiration_isnt_affected_by_request_format
draw do
get "/action_caching_test", to: "action_caching_test#index"
get "/action_caching_test/expire", to: "action_caching_test#expire"
end
get :index
cached_time = content_to_cache
@request.request_uri = "/action_caching_test/expire.xml"
get :expire, format: :xml
assert_response :success
get :index
assert_response :success
assert_not_equal cached_time, @response.body
end
def test_cache_expiration_with_url_string
draw do
get "/action_caching_test", to: "action_caching_test#index"
get "/action_caching_test/expire_with_url_string", to: "action_caching_test#expire_with_url_string"
end
get :index
cached_time = content_to_cache
@request.request_uri = "/action_caching_test/expire_with_url_string"
get :expire_with_url_string
assert_response :success
get :index
assert_response :success
assert_not_equal cached_time, @response.body
end
def test_cache_is_scoped_by_subdomain
draw do
get "/action_caching_test", to: "action_caching_test#index"
end
@request.host = "jamis.hostname.com"
get :index
assert_response :success
jamis_cache = content_to_cache
@request.host = "david.hostname.com"
get :index
assert_response :success
david_cache = content_to_cache
assert_not_equal jamis_cache, @response.body
@request.host = "jamis.hostname.com"
get :index
assert_response :success
assert_equal jamis_cache, @response.body
@request.host = "david.hostname.com"
get :index
assert_response :success
assert_equal david_cache, @response.body
end
def test_redirect_is_not_cached
draw do
get "/action_caching_test", to: "action_caching_test#index"
get "/action_caching_test/redirected", to: "action_caching_test#redirected"
end
get :redirected
assert_response :redirect
get :redirected
assert_response :redirect
end
def test_forbidden_is_not_cached
draw do
get "/action_caching_test/forbidden", to: "action_caching_test#forbidden"
end
get :forbidden
assert_response :forbidden
get :forbidden
assert_response :forbidden
end
def test_xml_version_of_resource_is_treated_as_different_cache
draw do
get "/action_caching_test/index", to: "action_caching_test#index"
get "/action_caching_test/expire_xml", to: "action_caching_test#expire_xml"
end
get :index, format: "xml"
assert_response :success
cached_time = content_to_cache
assert_equal cached_time, @response.body
assert fragment_exist?("hostname.com/action_caching_test/index.xml")
get :index, format: "xml"
assert_cached(cached_time, "application/xml")
get :expire_xml
assert_response :success
get :index, format: "xml"
assert_response :success
assert_not_equal cached_time, @response.body
end
def test_correct_content_type_is_returned_for_cache_hit
draw do
get "/action_caching_test/index/:id", to: "action_caching_test#index"
end
# run it twice to cache it the first time
get :index, params: { id: "content-type" }, format: "xml"
get :index, params: { id: "content-type" }, format: "xml"
assert_response :success
if @response.respond_to?(:media_type)
assert_equal "application/xml", @response.media_type
else
assert_equal "application/xml", @response.content_type
end
end
def test_correct_content_type_is_returned_for_cache_hit_on_action_with_string_key
draw do
get "/action_caching_test/show", to: "action_caching_test#show"
end
# run it twice to cache it the first time
get :show, format: "xml"
get :show, format: "xml"
assert_response :success
if @response.respond_to?(:media_type)
assert_equal "application/xml", @response.media_type
else
assert_equal "application/xml", @response.content_type
end
end
def test_correct_content_type_is_returned_for_cache_hit_on_action_with_string_key_from_proc
draw do
get "/action_caching_test/edit/:id", to: "action_caching_test#edit"
end
# run it twice to cache it the first time
get :edit, params: { id: 1 }, format: "xml"
get :edit, params: { id: 1 }, format: "xml"
assert_response :success
if @response.respond_to?(:media_type)
assert_equal "application/xml", @response.media_type
else
assert_equal "application/xml", @response.content_type
end
end
def test_empty_path_is_normalized
@mock_controller.mock_url_for = "http://example.org/"
@mock_controller.mock_path = "/"
assert_equal "example.org/index", @path_class.new(@mock_controller, {}).path
end
def test_file_extensions
draw do
get "/action_caching_test/index/*id", to: "action_caching_test#index", format: false
end
get :index, params: { id: "kitten.jpg" }
get :index, params: { id: "kitten.jpg" }
assert_response :success
end
if defined? ActiveRecord
def test_record_not_found_returns_404_for_multiple_requests
draw do
get "/action_caching_test/record_not_found", to: "action_caching_test#record_not_found"
end
get :record_not_found
assert_response 404
get :record_not_found
assert_response 404
end
end
def test_four_oh_four_returns_404_for_multiple_requests
draw do
get "/action_caching_test/four_oh_four", to: "action_caching_test#four_oh_four"
end
get :four_oh_four
assert_response 404
get :four_oh_four
assert_response 404
end
def test_four_oh_four_renders_content
draw do
get "/action_caching_test/four_oh_four", to: "action_caching_test#four_oh_four"
end
get :four_oh_four
assert_equal "404'd!", @response.body
end
def test_simple_runtime_error_returns_500_for_multiple_requests
draw do
get "/action_caching_test/simple_runtime_error", to: "action_caching_test#simple_runtime_error"
end
get :simple_runtime_error
assert_response 500
get :simple_runtime_error
assert_response 500
end
def test_action_caching_plus_streaming
draw do
get "/action_caching_test/streaming", to: "action_caching_test#streaming"
end
get :streaming
assert_response :success
assert_match(/streaming/, @response.body)
assert fragment_exist?("hostname.com/action_caching_test/streaming")
end
def test_invalid_format_returns_not_acceptable
draw do
get "/action_caching_test/invalid", to: "action_caching_test#invalid"
end
get :invalid, format: "json"
assert_response :success
cached_time = content_to_cache
assert_equal cached_time, @response.body
assert fragment_exist?("hostname.com/action_caching_test/invalid.json")
get :invalid, format: "json"
assert_response :success
assert_equal cached_time, @response.body
get :invalid, format: "xml"
assert_response :not_acceptable
get :invalid, format: "\xC3\x83"
assert_response :not_acceptable
end
def test_format_from_accept_header
draw do
get "/action_caching_test/accept", to: "action_caching_test#accept"
get "/action_caching_test/accept/expire", to: "action_caching_test#expire_accept"
end
# Cache the JSON format
get_json :accept
json_cached_time = content_to_cache
assert_cached json_cached_time, "application/json"
# Check that the JSON format is cached
get_json :accept
assert_cached json_cached_time, "application/json"
# Cache the HTML format
get_html :accept
html_cached_time = content_to_cache
assert_cached html_cached_time
# Check that it's not the JSON format
assert_not_equal json_cached_time, @response.body
# Check that the HTML format is cached
get_html :accept
assert_cached html_cached_time
# Check that the JSON format is still cached
get_json :accept
assert_cached json_cached_time, "application/json"
# Expire the JSON format
get_json :expire_accept
assert_response :success
# Check that the HTML format is still cached
get_html :accept
assert_cached html_cached_time
# Check the JSON format was expired
get_json :accept
new_json_cached_time = content_to_cache
assert_cached new_json_cached_time, "application/json"
assert_not_equal json_cached_time, @response.body
# Expire the HTML format
get_html :expire_accept
assert_response :success
# Check that the JSON format is still cached
get_json :accept
assert_cached new_json_cached_time, "application/json"
# Check the HTML format was expired
get_html :accept
new_html_cached_time = content_to_cache
assert_cached new_html_cached_time
assert_not_equal html_cached_time, @response.body
end
def test_explicit_html_format_is_used_for_fragment_path
draw do
get "/action_caching_test/accept", to: "action_caching_test#accept"
get "/action_caching_test/accept/expire", to: "action_caching_test#expire_accept"
end
get :accept, format: "html"
cached_time = content_to_cache
assert_cached cached_time
assert fragment_exist?("hostname.com/action_caching_test/accept.html")
get :accept, format: "html"
cached_time = content_to_cache
assert_cached cached_time
get :expire_accept, format: "html"
assert_response :success
assert !fragment_exist?("hostname.com/action_caching_test/accept.html")
get :accept, format: "html"
assert_not_cached cached_time
end
def test_lambda_arity_with_cache_path
draw do
get "/action_caching_test/not_url_cache_path_no_args", to: "action_caching_test#not_url_cache_path_no_args"
end
get :not_url_cache_path_no_args
assert_response :success
assert !fragment_exist?("test.host/action_caching_test/not_url_cache_path_no_args")
assert fragment_exist?("not_url_cache_path_no_args_key")
end
def test_lambda_arity_with_layout
draw do
get "/action_caching_test/with_layout_proc_param_no_args", to: "action_caching_test#with_layout_proc_param_no_args"
end
get :with_layout_proc_param_no_args, params: { title: "Request 1", layout: "false" }
assert_response :success
cached_time = content_to_cache
assert_equal "Request 1\n#{cached_time}", @response.body
assert_equal cached_time, read_fragment("hostname.com/action_caching_test/with_layout_proc_param_no_args")
get :with_layout_proc_param_no_args, params: { title: "Request 2", layout: "false" }
assert_response :success
assert_equal "Request 2\n#{cached_time}", @response.body
assert_equal cached_time, read_fragment("hostname.com/action_caching_test/with_layout_proc_param_no_args")
end
private
def get_html(*args)
@request.accept = "text/html"
get(*args)
end
def get_json(*args)
@request.accept = "application/json"
get(*args)
end
def assert_cached(cache_time, media_type = "text/html")
assert_response :success
assert_equal cache_time, @response.body
if @response.respond_to?(:media_type)
assert_equal media_type, @response.media_type
else
assert_equal media_type, @response.content_type
end
end
def assert_not_cached(cache_time, media_type = "text/html")
assert_response :success
assert_not_equal cache_time, @response.body
if @response.respond_to?(:media_type)
assert_equal media_type, @response.media_type
else
assert_equal media_type, @response.content_type
end
end
def content_to_cache
@controller.instance_variable_get(:@cache_this)
end
def fragment_exist?(path)
@controller.fragment_exist?(path)
end
def read_fragment(path)
@controller.read_fragment(path)
end
def draw(&block)
@routes = ActionDispatch::Routing::RouteSet.new
@routes.draw(&block)
@controller.extend(@routes.url_helpers)
end
if ActionPack::VERSION::STRING < "5.0"
def get(action, options = {})
format = options.slice(:format)
params = options[:params] || {}
session = options[:session] || {}
flash = options[:flash] || {}
super(action, params.merge(format), session, flash)
end
end
end
actionpack-action_caching-1.2.2/actionpack-action_caching.gemspec 0000644 0000041 0000041 00000002463 14053115675 025233 0 ustar www-data www-data Gem::Specification.new do |gem|
gem.name = "actionpack-action_caching"
gem.version = "1.2.2"
gem.author = "David Heinemeier Hansson"
gem.email = "david@loudthinking.com"
gem.description = "Action caching for Action Pack (removed from core in Rails 4.0)"
gem.summary = "Action caching for Action Pack (removed from core in Rails 4.0)"
gem.homepage = "https://github.com/rails/actionpack-action_caching"
gem.metadata = {
"bug_tracker_uri" => "https://github.com/rails/actionpack-action_caching/issues",
"changelog_uri" => "https://github.com/rails/actionpack-action_caching/blob/v#{gem.version}/CHANGELOG.md",
"documentation_uri" => "https://www.rubydoc.info/gems/actionpack-action_caching/#{gem.version}",
"source_code_uri" => "https://github.com/rails/actionpack-action_caching/tree/v#{gem.version}",
}
gem.required_ruby_version = ">= 1.9.3"
gem.files = `git ls-files`.split($/)
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
gem.require_paths = ["lib"]
gem.license = "MIT"
gem.add_dependency "actionpack", ">= 4.0.0"
gem.add_development_dependency "mocha"
gem.add_development_dependency "activerecord", ">= 4.0.0"
end
actionpack-action_caching-1.2.2/README.md 0000644 0000041 0000041 00000010245 14053115675 020077 0 ustar www-data www-data actionpack-action_caching
=========================
Action caching for Action Pack (removed from core in Rails 4.0).
Installation
------------
Add this line to your application's Gemfile:
```ruby
gem 'actionpack-action_caching'
```
And then execute:
$ bundle
Or install it yourself as:
$ gem install actionpack-action_caching
Usage
-----
Action caching is similar to page caching by the fact that the entire
output of the response is cached, but unlike page caching, every
request still goes through Action Pack. The key benefit of this is
that filters run before the cache is served, which allows for
authentication and other restrictions on whether someone is allowed
to execute such action.
```ruby
class ListsController < ApplicationController
before_action :authenticate, except: :public
caches_page :public
caches_action :index, :show
end
```
In this example, the `public` action doesn't require authentication
so it's possible to use the faster page caching. On the other hand
`index` and `show` require authentication. They can still be cached,
but we need action caching for them.
Action caching uses fragment caching internally and an around
filter to do the job. The fragment cache is named according to
the host and path of the request. A page that is accessed at
`http://david.example.com/lists/show/1` will result in a fragment named
`david.example.com/lists/show/1`. This allows the cacher to
differentiate between `david.example.com/lists/` and
`jamis.example.com/lists/` -- which is a helpful way of assisting
the subdomain-as-account-key pattern.
Different representations of the same resource, e.g.
`http://david.example.com/lists` and
`http://david.example.com/lists.xml`
are treated like separate requests and so are cached separately.
Keep in mind when expiring an action cache that
`action: "lists"` is not the same as
`action: "list", format: :xml`.
You can modify the default action cache path by passing a
`:cache_path` option. This will be passed directly to
`ActionCachePath.new`. This is handy for actions with
multiple possible routes that should be cached differently. If a
proc (or an object that responds to `to_proc`) is given, it is
called with the current controller instance.
And you can also use `:if` (or `:unless`) to control when the action
should be cached, similar to how you use them with `before_action`.
As of Rails 3.0, you can also pass `:expires_in` with a time
interval (in seconds) to schedule expiration of the cached item.
The following example depicts some of the points made above:
```ruby
class ListsController < ApplicationController
before_action :authenticate, except: :public
# simple fragment cache
caches_action :current
# expire cache after an hour
caches_action :archived, expires_in: 1.hour
# cache unless it's a JSON request
caches_action :index, unless: -> { request.format.json? }
# custom cache path
caches_action :show, cache_path: { project: 1 }
# custom cache path with a proc
caches_action :history, cache_path: -> { request.domain }
# custom cache path with a symbol
caches_action :feed, cache_path: :user_cache_path
protected
def user_cache_path
if params[:user_id]
user_list_url(params[:user_id], params[:id])
else
list_url(params[:id])
end
end
end
```
If you pass `layout: false`, it will only cache your action
content. That's useful when your layout has dynamic information.
Note: Both the `:format` param and the `Accept` header are taken
into account when caching the fragment with the `:format` having
precedence. For backwards compatibility when the `Accept` header
indicates a HTML request the fragment is stored without the
extension but if an explicit `"html"` is passed in `:format` then
that _is_ used for storing the fragment.
Contributing
------------
1. Fork it.
2. Create your feature branch (`git checkout -b my-new-feature`).
3. Commit your changes (`git commit -am 'Add some feature'`).
4. Push to the branch (`git push origin my-new-feature`).
5. Create a new Pull Request.
Code Status
-----------
* [](https://travis-ci.org/rails/actionpack-action_caching)
actionpack-action_caching-1.2.2/gemfiles/ 0000755 0000041 0000041 00000000000 14053115675 020411 5 ustar www-data www-data actionpack-action_caching-1.2.2/gemfiles/Gemfile-5-2-stable 0000644 0000041 0000041 00000000154 14053115675 023455 0 ustar www-data www-data source "https://rubygems.org"
gemspec path: ".."
gem "rails", github: "rails/rails", branch: "5-2-stable"
actionpack-action_caching-1.2.2/gemfiles/Gemfile-5-0-stable 0000644 0000041 0000041 00000000154 14053115675 023453 0 ustar www-data www-data source "https://rubygems.org"
gemspec path: ".."
gem "rails", github: "rails/rails", branch: "5-0-stable"
actionpack-action_caching-1.2.2/gemfiles/Gemfile-4-2-stable 0000644 0000041 0000041 00000000273 14053115675 023456 0 ustar www-data www-data source "https://rubygems.org"
gemspec path: ".."
gem "rails", github: "rails/rails", branch: "4-2-stable"
gem "mime-types", "< 3"
if RUBY_VERSION < "2.1"
gem "nokogiri", "< 1.7"
end
actionpack-action_caching-1.2.2/gemfiles/Gemfile-edge 0000644 0000041 0000041 00000000240 14053115675 022602 0 ustar www-data www-data source "https://rubygems.org"
gemspec path: ".."
gem "rails", github: "rails/rails", branch: "main"
gem "activerecord", github: "rails/rails", branch: "main"
actionpack-action_caching-1.2.2/gemfiles/Gemfile-5-1-stable 0000644 0000041 0000041 00000000154 14053115675 023454 0 ustar www-data www-data source "https://rubygems.org"
gemspec path: ".."
gem "rails", github: "rails/rails", branch: "5-1-stable"
actionpack-action_caching-1.2.2/gemfiles/Gemfile-6-0-stable 0000644 0000041 0000041 00000000154 14053115675 023454 0 ustar www-data www-data source "https://rubygems.org"
gemspec path: ".."
gem "rails", github: "rails/rails", branch: "6-0-stable"
actionpack-action_caching-1.2.2/gemfiles/Gemfile-6-1-stable 0000644 0000041 0000041 00000000154 14053115675 023455 0 ustar www-data www-data source "https://rubygems.org"
gemspec path: ".."
gem "rails", github: "rails/rails", branch: "6-1-stable"
actionpack-action_caching-1.2.2/CHANGELOG.md 0000644 0000041 0000041 00000002643 14053115675 020434 0 ustar www-data www-data ## 1.2.2 (May 10, 2021)
* Add support for Rails 6.1
*Jonathan Fleckenstein*, *Prem Sichanugrist*
## 1.2.1 (November 12, 2019)
* Fix HTML escaping when `:layout` is `false`.
*Anton Katunin*
* Add support to Rails 6.
*Jacob Bednarz*
## 1.2.0 (January 23, 2017)
* Support proc options with zero arguments
Fixes #40.
*Andrew White*
* The options `:layout` and `:cache_path` now behave the same when
passed a `Symbol`, `Proc` or object that responds to call.
*Andrew White*
* Respect `Accept` header when caching actions
Fixes #18.
*Andrew White*
* Support Rails 4.0, 4.1, 4.2, 5.0 and edge
*Eileen Uchitelle*, *Andrew White*
* Call `to_s` on the extension as it may be a symbol
Fixes #10.
*Andrew White*
## 1.1.1 (January 2, 2014)
* Fix load order problem with other gems
*Andrew White*
## 1.1.0 (November 1, 2013)
* Allow to use non-proc object in `cache_path` option. You can pass an object that
responds to a `call` method.
Example:
class CachePath
def call(controller)
controller.id
end
end
class TestController < ApplicationController
caches_action :index, :cache_path => CachePath.new
def index; end
end
*Piotr Niełacny*
## 1.0.0 (February 28, 2013)
* Extract Action Pack - Action Caching from Rails core.
*Francesco Rodriguez*
actionpack-action_caching-1.2.2/.rubocop.yml 0000644 0000041 0000041 00000005070 14053115675 021072 0 ustar www-data www-data AllCops:
TargetRubyVersion: 2.2
# RuboCop has a bunch of cops enabled by default. This setting tells RuboCop
# to ignore them, so only the ones explicitly set in this file are enabled.
DisabledByDefault: true
# Prefer &&/|| over and/or.
Style/AndOr:
Enabled: true
# Do not use braces for hash literals when they are the last argument of a
# method call.
Style/BracesAroundHashParameters:
Enabled: true
# Align `when` with `case`.
Style/CaseIndentation:
Enabled: true
# Align comments with method definitions.
Style/CommentIndentation:
Enabled: true
# No extra empty lines.
Style/EmptyLines:
Enabled: true
# In a regular class definition, no empty lines around the body.
Style/EmptyLinesAroundClassBody:
Enabled: true
# In a regular module definition, no empty lines around the body.
Style/EmptyLinesAroundModuleBody:
Enabled: true
# Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
Style/HashSyntax:
Enabled: true
# Method definitions after `private` or `protected` isolated calls need one
# extra level of indentation.
Style/IndentationConsistency:
Enabled: true
EnforcedStyle: rails
# Two spaces, no tabs (for indentation).
Style/IndentationWidth:
Enabled: true
Style/SpaceAfterColon:
Enabled: true
Style/SpaceAfterComma:
Enabled: true
Style/SpaceAroundEqualsInParameterDefault:
Enabled: true
Style/SpaceAroundKeyword:
Enabled: true
Style/SpaceAroundOperators:
Enabled: true
Style/SpaceBeforeFirstArg:
Enabled: true
# Defining a method with parameters needs parentheses.
Style/MethodDefParentheses:
Enabled: true
# Use `foo {}` not `foo{}`.
Style/SpaceBeforeBlockBraces:
Enabled: true
# Use `foo { bar }` not `foo {bar}`.
Style/SpaceInsideBlockBraces:
Enabled: true
# Use `{ a: 1 }` not `{a:1}`.
Style/SpaceInsideHashLiteralBraces:
Enabled: true
Style/SpaceInsideParens:
Enabled: true
# Check quotes usage according to lint rule below.
Style/StringLiterals:
Enabled: true
EnforcedStyle: double_quotes
# Detect hard tabs, no hard tabs.
Style/Tab:
Enabled: true
# Blank lines should not have any spaces.
Style/TrailingBlankLines:
Enabled: true
# No trailing whitespace.
Style/TrailingWhitespace:
Enabled: true
# Use quotes for string literals when they are enough.
Style/UnneededPercentQ:
Enabled: true
# Align `end` with the matching keyword or starting expression except for
# assignments, where it should be aligned with the LHS.
Lint/EndAlignment:
Enabled: true
AlignWith: variable
# Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
Lint/RequireParentheses:
Enabled: true
actionpack-action_caching-1.2.2/.gitignore 0000644 0000041 0000041 00000000072 14053115675 020605 0 ustar www-data www-data .ruby-version
Gemfile.lock
gemfiles/*.lock
pkg/*
test/tmp
actionpack-action_caching-1.2.2/.codeclimate.yml 0000644 0000041 0000041 00000000105 14053115675 021664 0 ustar www-data www-data engines:
rubocop:
enabled: true
ratings:
paths:
- "**.rb"
actionpack-action_caching-1.2.2/Rakefile 0000644 0000041 0000041 00000000311 14053115675 020256 0 ustar www-data www-data #!/usr/bin/env rake
require "bundler/gem_tasks"
require "rake/testtask"
Rake::TestTask.new do |t|
t.libs = ["test"]
t.pattern = "test/**/*_test.rb"
t.ruby_opts = ["-w"]
end
task default: :test
actionpack-action_caching-1.2.2/lib/ 0000755 0000041 0000041 00000000000 14053115675 017364 5 ustar www-data www-data actionpack-action_caching-1.2.2/lib/actionpack/ 0000755 0000041 0000041 00000000000 14053115675 021500 5 ustar www-data www-data actionpack-action_caching-1.2.2/lib/actionpack/action_caching.rb 0000644 0000041 0000041 00000000054 14053115675 024755 0 ustar www-data www-data require "actionpack/action_caching/railtie"
actionpack-action_caching-1.2.2/lib/actionpack/action_caching/ 0000755 0000041 0000041 00000000000 14053115675 024431 5 ustar www-data www-data actionpack-action_caching-1.2.2/lib/actionpack/action_caching/railtie.rb 0000644 0000041 0000041 00000000451 14053115675 026407 0 ustar www-data www-data require "rails/railtie"
module ActionPack
module ActionCaching
class Railtie < Rails::Railtie
initializer "action_pack.action_caching" do
ActiveSupport.on_load(:action_controller) do
require "action_controller/action_caching"
end
end
end
end
end
actionpack-action_caching-1.2.2/lib/action_controller/ 0000755 0000041 0000041 00000000000 14053115675 023104 5 ustar www-data www-data actionpack-action_caching-1.2.2/lib/action_controller/action_caching.rb 0000644 0000041 0000041 00000000432 14053115675 026361 0 ustar www-data www-data require "action_controller/caching/actions"
module ActionController
module Caching
extend ActiveSupport::Autoload
eager_autoload do
autoload :Actions
end
include Actions
end
end
ActionController::Base.send(:include, ActionController::Caching::Actions)
actionpack-action_caching-1.2.2/lib/action_controller/caching/ 0000755 0000041 0000041 00000000000 14053115675 024500 5 ustar www-data www-data actionpack-action_caching-1.2.2/lib/action_controller/caching/actions.rb 0000644 0000041 0000041 00000021550 14053115675 026470 0 ustar www-data www-data require "set"
module ActionController
module Caching
# Action caching is similar to page caching by the fact that the entire
# output of the response is cached, but unlike page caching, every
# request still goes through Action Pack. The key benefit of this is
# that filters run before the cache is served, which allows for
# authentication and other restrictions on whether someone is allowed
# to execute such action.
#
# class ListsController < ApplicationController
# before_action :authenticate, except: :public
#
# caches_page :public
# caches_action :index, :show
# end
#
# In this example, the +public+ action doesn't require authentication
# so it's possible to use the faster page caching. On the other hand
# +index+ and +show+ require authentication. They can still be cached,
# but we need action caching for them.
#
# Action caching uses fragment caching internally and an around
# filter to do the job. The fragment cache is named according to
# the host and path of the request. A page that is accessed at
# http://david.example.com/lists/show/1 will result in a fragment named
# david.example.com/lists/show/1. This allows the cacher to
# differentiate between david.example.com/lists/ and
# jamis.example.com/lists/ -- which is a helpful way of assisting
# the subdomain-as-account-key pattern.
#
# Different representations of the same resource, e.g.
# http://david.example.com/lists and
# http://david.example.com/lists.xml
# are treated like separate requests and so are cached separately.
# Keep in mind when expiring an action cache that
# action: "lists" is not the same as
# action: "lists", format: :xml.
#
# You can modify the default action cache path by passing a
# :cache_path option. This will be passed directly to
# ActionCachePath.new. This is handy for actions with
# multiple possible routes that should be cached differently. If a
# block is given, it is called with the current controller instance.
# If an object that responds to call is given, it'll be called
# with the current controller instance.
#
# And you can also use :if (or :unless) to pass a
# proc that specifies when the action should be cached.
#
# As of Rails 3.0, you can also pass :expires_in with a time
# interval (in seconds) to schedule expiration of the cached item.
#
# The following example depicts some of the points made above:
#
# class CachePathCreator
# def initialize(name)
# @name = name
# end
#
# def call(controller)
# "cache-path-#{@name}"
# end
# end
#
#
# class ListsController < ApplicationController
# before_action :authenticate, except: :public
#
# caches_page :public
#
# caches_action :index, if: Proc.new do
# !request.format.json? # cache if is not a JSON request
# end
#
# caches_action :show, cache_path: { project: 1 },
# expires_in: 1.hour
#
# caches_action :feed, cache_path: Proc.new do
# if params[:user_id]
# user_list_url(params[:user_id, params[:id])
# else
# list_url(params[:id])
# end
# end
#
# caches_action :posts, cache_path: CachePathCreator.new("posts")
# end
#
# If you pass layout: false, it will only cache your action
# content. That's useful when your layout has dynamic information.
#
# Warning: If the format of the request is determined by the Accept HTTP
# header the Content-Type of the cached response could be wrong because
# no information about the MIME type is stored in the cache key. So, if
# you first ask for MIME type M in the Accept header, a cache entry is
# created, and then perform a second request to the same resource asking
# for a different MIME type, you'd get the content cached for M.
#
# The :format parameter is taken into account though. The safest
# way to cache by MIME type is to pass the format in the route.
module Actions
extend ActiveSupport::Concern
module ClassMethods
# Declares that +actions+ should be cached.
# See ActionController::Caching::Actions for details.
def caches_action(*actions)
return unless cache_configured?
options = actions.extract_options!
options[:layout] = true unless options.key?(:layout)
filter_options = options.extract!(:if, :unless).merge(only: actions)
cache_options = options.extract!(:layout, :cache_path).merge(store_options: options)
around_action ActionCacheFilter.new(cache_options), filter_options
end
end
def _save_fragment(name, options)
content = ""
response_body.each do |parts|
content << parts
end
if caching_allowed?
write_fragment(name, content, options)
else
content
end
end
def caching_allowed?
(request.get? || request.head?) && response.status == 200
end
protected
def expire_action(options = {})
return unless cache_configured?
if options.is_a?(Hash) && options[:action].is_a?(Array)
options[:action].each { |action| expire_action(options.merge(action: action)) }
else
expire_fragment(ActionCachePath.new(self, options, false).path)
end
end
class ActionCacheFilter # :nodoc:
def initialize(options, &block)
@cache_path, @store_options, @cache_layout =
options.values_at(:cache_path, :store_options, :layout)
end
def around(controller)
cache_layout = expand_option(controller, @cache_layout)
path_options = expand_option(controller, @cache_path)
cache_path = ActionCachePath.new(controller, path_options || {})
body = controller.read_fragment(cache_path.path, @store_options)
unless body
controller.action_has_layout = false unless cache_layout
yield
controller.action_has_layout = true
body = controller._save_fragment(cache_path.path, @store_options)
end
body = render_to_string(controller, body) unless cache_layout
controller.response_body = body
controller.content_type = Mime[cache_path.extension || :html]
end
if ActionPack::VERSION::STRING < "4.1"
def render_to_string(controller, body)
controller.render_to_string(text: body, layout: true)
end
else
def render_to_string(controller, body)
controller.render_to_string(html: body.html_safe, layout: true)
end
end
private
def expand_option(controller, option)
option = option.to_proc if option.respond_to?(:to_proc)
if option.is_a?(Proc)
case option.arity
when -2, -1, 1
controller.instance_exec(controller, &option)
when 0
controller.instance_exec(&option)
else
raise ArgumentError, "Invalid proc arity of #{option.arity} - proc options should have an arity of 0 or 1"
end
elsif option.respond_to?(:call)
option.call(controller)
else
option
end
end
end
class ActionCachePath
attr_reader :path, :extension
# If +infer_extension+ is +true+, the cache path extension is looked up from the request's
# path and format. This is desirable when reading and writing the cache, but not when
# expiring the cache - +expire_action+ should expire the same files regardless of the
# request format.
def initialize(controller, options = {}, infer_extension = true)
if infer_extension
if controller.params.key?(:format)
@extension = controller.params[:format]
elsif !controller.request.format.html?
@extension = controller.request.format.to_sym
else
@extension = nil
end
options.reverse_merge!(format: @extension) if options.is_a?(Hash)
end
path = controller.url_for(options).split("://", 2).last
@path = normalize!(path)
end
private
def normalize!(path)
ext = URI::DEFAULT_PARSER.escape(extension.to_s) if extension
path << "index" if path[-1] == ?/
path << ".#{ext}" if extension && !path.split("?", 2).first.end_with?(".#{ext}")
URI::DEFAULT_PARSER.unescape(path)
end
end
end
end
end
actionpack-action_caching-1.2.2/Gemfile 0000644 0000041 0000041 00000000064 14053115675 020111 0 ustar www-data www-data source "https://rubygems.org"
gemspec
gem "rails"
actionpack-action_caching-1.2.2/.github/ 0000755 0000041 0000041 00000000000 14053115675 020156 5 ustar www-data www-data actionpack-action_caching-1.2.2/.github/workflows/ 0000755 0000041 0000041 00000000000 14053115675 022213 5 ustar www-data www-data actionpack-action_caching-1.2.2/.github/workflows/ci.yml 0000644 0000041 0000041 00000003350 14053115675 023332 0 ustar www-data www-data name: CI
on:
push:
branches:
- 'master'
pull_request:
jobs:
build:
strategy:
matrix:
gemfile:
- '4-2-stable'
- '5-0-stable'
- '5-1-stable'
- '5-2-stable'
- '6-0-stable'
- '6-1-stable'
- 'edge'
ruby:
- '2.4'
- '2.5'
- '2.6'
- '2.7'
- '3.0'
exclude:
- gemfile: '4-2-stable'
ruby: '2.5'
- gemfile: '4-2-stable'
ruby: '2.6'
- gemfile: '4-2-stable'
ruby: '2.7'
- gemfile: '4-2-stable'
ruby: '3.0'
- gemfile: '5-0-stable'
ruby: '2.7'
- gemfile: '5-0-stable'
ruby: '3.0'
- gemfile: '5-1-stable'
ruby: '2.7'
- gemfile: '5-1-stable'
ruby: '3.0'
- gemfile: '5-2-stable'
ruby: '2.7'
- gemfile: '5-2-stable'
ruby: '3.0'
- gemfile: '6-0-stable'
ruby: '2.4'
- gemfile: '6-1-stable'
ruby: '2.4'
- gemfile: 'edge'
ruby: '2.4'
- gemfile: 'edge'
ruby: '2.5'
- gemfile: 'edge'
ruby: '2.6'
fail-fast: false
runs-on: ubuntu-latest
name: ${{ matrix.ruby }} rails-${{ matrix.gemfile }}
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
bundler: ${{ fromJSON('["2", "1"]')[matrix.ruby == '2.4'] }}
- run: bundle exec rake test
env:
BUNDLE_GEMFILE: gemfiles/Gemfile-${{ matrix.gemfile }}
BUNDLE_JOBS: 4
BUNDLE_RETRY: 3
actionpack-action_caching-1.2.2/LICENSE.txt 0000644 0000041 0000041 00000002071 14053115675 020441 0 ustar www-data www-data Copyright (c) 2012 David Heinemeier Hansson
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.