diff --git a/README.md b/README.md index e8eedfe..f2dbdfe 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,10 @@ 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. +You can also modify the expires in by passing a symbol as `:set_expires_in`. +This is useful if you need different expire times in your action or if you use +a concern to set `caches_action` and your controllers must have different +expire times. The following example depicts some of the points made above: @@ -86,6 +90,9 @@ class ListsController < ApplicationController # expire cache after an hour caches_action :archived, expires_in: 1.hour + # custom expire cache + caches_action :archived, expires_in: :set_expires_in + # cache unless it's a JSON request caches_action :index, unless: -> { request.format.json? } @@ -106,6 +113,14 @@ class ListsController < ApplicationController list_url(params[:id]) end end + + def set_expires_in + if params[:user_id] + 2.hours + else + 48.hours + end + end end ``` diff --git a/lib/action_controller/caching/actions.rb b/lib/action_controller/caching/actions.rb index 8c0ee84..073048e 100644 --- a/lib/action_controller/caching/actions.rb +++ b/lib/action_controller/caching/actions.rb @@ -111,7 +111,7 @@ def caches_action(*actions) 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) + cache_options = options.extract!(:layout, :cache_path, :expires_in).merge(store_options: options) around_action ActionCacheFilter.new(cache_options), filter_options end @@ -147,22 +147,24 @@ def expire_action(options = {}) class ActionCacheFilter # :nodoc: def initialize(options, &block) - @cache_path, @store_options, @cache_layout = - options.values_at(:cache_path, :store_options, :layout) + @cache_path, @cache_layout, @expires_in, @store_options = + options.values_at(:cache_path, :layout, :expires_in, :store_options) end def around(controller) cache_layout = expand_option(controller, @cache_layout) path_options = expand_option(controller, @cache_path) + expires_in = expand_option(controller, @expires_in) + store_options = @store_options.merge(expires_in: expires_in) cache_path = ActionCachePath.new(controller, path_options || {}) - body = controller.read_fragment(cache_path.path, @store_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) + body = controller._save_fragment(cache_path.path, store_options) end body = render_to_string(controller, body) unless cache_layout diff --git a/test/caching_test.rb b/test/caching_test.rb index 0805256..d248d61 100644 --- a/test/caching_test.rb +++ b/test/caching_test.rb @@ -18,6 +18,12 @@ def call(controller) end end +class ExpiresIn + def call(controller) + 1.hour + end +end + class ActionCachingTestController < CachingController rescue_from(Exception) { head 500 } rescue_from(ActionController::UnknownFormat) { head :not_acceptable } @@ -36,6 +42,8 @@ class ActionCachingTestController < CachingController 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 :custom_expires_in, expires_in: ExpiresIn.new + caches_action :symbol_expires_in, expires_in: :expires_in_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" @@ -102,6 +110,8 @@ def simple_runtime_error alias_method :destroy, :index alias_method :custom_cache_path, :index alias_method :symbol_cache_path, :index + alias_method :custom_expires_in, :index + alias_method :symbol_expires_in, :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 @@ -121,6 +131,16 @@ def expire_with_url_string head :ok end + def expire_symbol_expires_in + expire_action controller: "action_caching_test", action: "symbol_expires_in" + head :ok + end + + def expire_custom_expires_in + expire_action controller: "action_caching_test", action: "custom_expires_in" + head :ok + end + def streaming render plain: "streaming", stream: true end @@ -159,6 +179,10 @@ def cache_path_protected_method ["controller", params[:id]].compact.join("-") end + def expires_in_protected_method + 1.hour + end + if ActionPack::VERSION::STRING < "4.1" def render(options) if options.key?(:plain) @@ -484,6 +508,60 @@ def test_cache_expiration assert_equal new_cached_time, @response.body end + def test_cache_expiration_with_symbol + draw do + get "/action_caching_test/symbol_expires_in", to: "action_caching_test#symbol_expires_in" + get "/action_caching_test/expire", to: "action_caching_test#expire_symbol_expires_in" + end + + get :symbol_expires_in + assert_response :success + cached_time = content_to_cache + + get :symbol_expires_in + assert_response :success + assert_equal cached_time, @response.body + + get :expire_symbol_expires_in + assert_response :success + + get :symbol_expires_in + assert_response :success + new_cached_time = content_to_cache + assert_not_equal cached_time, @response.body + + get :symbol_expires_in + assert_response :success + assert_equal new_cached_time, @response.body + end + + def test_cache_expiration_with_custom_object + draw do + get "/action_caching_test/symbol_expires_in", to: "action_caching_test#custom_expires_in" + get "/action_caching_test/expire", to: "action_caching_test#expire_custom_expires_in" + end + + get :custom_expires_in + assert_response :success + cached_time = content_to_cache + + get :custom_expires_in + assert_response :success + assert_equal cached_time, @response.body + + get :expire_custom_expires_in + assert_response :success + + get :custom_expires_in + assert_response :success + new_cached_time = content_to_cache + assert_not_equal cached_time, @response.body + + get :custom_expires_in + 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"