2009-05-11 13:57:59 -04:00
module ActionController
module ConditionalGet
2009-05-28 12:35:36 -04:00
extend ActiveSupport :: Concern
2009-05-27 04:40:43 -04:00
2009-12-20 21:05:26 -05:00
include RackDelegation
2009-10-26 20:13:43 -04:00
include Head
2009-05-28 10:49:02 -04:00
2009-05-11 13:57:59 -04:00
# Sets the etag, last_modified, or both on the response and renders a
# "304 Not Modified" response if the request is already fresh.
#
# Parameters:
# * <tt>:etag</tt>
2009-05-28 10:49:02 -04:00
# * <tt>:last_modified</tt>
2009-05-11 13:57:59 -04:00
# * <tt>:public</tt> By default the Cache-Control header is private, set this to true if you want your application to be cachable by other devices (proxy caches).
#
# Example:
#
# def show
# @article = Article.find(params[:id])
# fresh_when(:etag => @article, :last_modified => @article.created_at.utc, :public => true)
# end
#
# This will render the show template if the request isn't sending a matching etag or
# If-Modified-Since header and just a "304 Not Modified" response if there's a match.
2009-05-28 10:49:02 -04:00
#
2009-05-11 13:57:59 -04:00
def fresh_when ( options )
options . assert_valid_keys ( :etag , :last_modified , :public )
response . etag = options [ :etag ] if options [ :etag ]
response . last_modified = options [ :last_modified ] if options [ :last_modified ]
2009-10-26 20:13:43 -04:00
response . cache_control [ :public ] = true if options [ :public ]
2009-05-28 10:49:02 -04:00
2009-10-26 20:13:43 -04:00
head :not_modified if request . fresh? ( response )
2009-05-28 10:49:02 -04:00
end
2009-05-11 15:04:43 -04:00
# Sets the etag and/or last_modified on the response and checks it against
# the client request. If the request doesn't match the options provided, the
# request is considered stale and should be generated from scratch. Otherwise,
# it's fresh and we don't need to generate anything and a reply of "304 Not Modified" is sent.
#
# Parameters:
# * <tt>:etag</tt>
2009-05-28 10:49:02 -04:00
# * <tt>:last_modified</tt>
2009-05-11 15:04:43 -04:00
# * <tt>:public</tt> By default the Cache-Control header is private, set this to true if you want your application to be cachable by other devices (proxy caches).
#
# Example:
#
# def show
# @article = Article.find(params[:id])
#
# if stale?(:etag => @article, :last_modified => @article.created_at.utc)
# @statistics = @article.really_expensive_call
# respond_to do |format|
# # all the supported formats
# end
# end
# end
def stale? ( options )
fresh_when ( options )
! request . fresh? ( response )
end
2009-05-28 10:49:02 -04:00
2009-05-11 15:04:43 -04:00
# Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a "private" instruction, so that
# intermediate caches shouldn't cache the response.
#
# Examples:
# expires_in 20.minutes
# expires_in 3.hours, :public => true
# expires in 3.hours, 'max-stale' => 5.hours, :public => true
#
# This method will overwrite an existing Cache-Control header.
# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
def expires_in ( seconds , options = { } ) #:doc:
2009-07-31 00:00:39 -04:00
response . cache_control . merge! ( :max_age = > seconds , :public = > options . delete ( :public ) )
options . delete ( :private )
2009-05-11 15:04:43 -04:00
2009-07-31 00:00:39 -04:00
response . cache_control [ :extras ] = options . map { | k , v | " #{ k } = #{ v } " }
2009-05-11 15:04:43 -04:00
end
# Sets a HTTP 1.1 Cache-Control header of "no-cache" so no caching should occur by the browser or
# intermediate caches (like caching proxy servers).
def expires_now #:doc:
2009-10-26 20:32:42 -04:00
response . cache_control . replace ( :no_cache = > true )
2009-05-11 15:04:43 -04:00
end
2009-05-11 13:57:59 -04:00
end
2009-05-28 10:49:02 -04:00
end