From 9acb88e666269204821b78bec7b72d3d16597096 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 21 Oct 2008 02:30:13 +0200 Subject: Added stale?/fresh? and fresh_when methods to provide a layer of abstraction above request.fresh? and friends [DHH] --- actionpack/lib/action_controller/base.rb | 70 ++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 17 deletions(-) (limited to 'actionpack/lib/action_controller/base.rb') diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 3ede681253..4c5c5ac597 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -965,22 +965,6 @@ module ActionController #:nodoc: render :nothing => true, :status => status end - # Sets the Last-Modified response header. Returns 304 Not Modified if the - # If-Modified-Since request header is <= last modified. - def last_modified!(utc_time) - response.last_modified= utc_time - if request.if_modified_since && request.if_modified_since <= utc_time - head(:not_modified) - end - end - - # Sets the ETag response header. Returns 304 Not Modified if the - # If-None-Match request header matches. - def etag!(etag) - response.etag = etag - head(:not_modified) if response.etag == request.if_none_match - end - # Clears the rendered results, allowing for another render to be performed. def erase_render_results #:nodoc: response.body = nil @@ -1090,6 +1074,54 @@ module ActionController #:nodoc: @performed_redirect = true end + # 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 can rely on the default + # reply of "304 Not Modified". + # + # 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 + + # The opposite of stale? provided for parity when that feels more natural. + def fresh?(options) + !stale?(options) + end + + # Sets the etag, last_modified, or both such that the request can be short-circuited + # with a "304 Not Modified" response instead of rendering a template when the request + # is already fresh. + # + # Example: + # + # def show + # @article = Article.find(params[:id]) + # fresh_when(:etag => @article, :last_modified => @article.created_at.utc) + # 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. + def fresh_when(options) + options.assert_valid_keys(:etag, :last_modified) + + response.etag = options[:etag] if options[:etag] + response.last_modified = options[:last_modified] if options[:last_modified] + end + # Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a "private" instruction, so that # intermediate caches shouldn't cache the response. # @@ -1176,7 +1208,11 @@ module ActionController #:nodoc: end def default_render #:nodoc: - render + if request.fresh?(response) + head :not_modified + else + render + end end def perform_action -- cgit v1.2.3