Ported fresh_when into a ConditionalGet module

This commit is contained in:
Yehuda Katz + Carl Lerche
2009-05-11 10:57:59 -07:00
parent 030dfe3f83
commit a2f3684cec
5 changed files with 92 additions and 0 deletions

View File

@@ -1,5 +1,6 @@
module ActionController
autoload :Base, "action_controller/new_base/base"
autoload :ConditionalGet, "action_controller/new_base/conditional_get"
autoload :HideActions, "action_controller/new_base/hide_actions"
autoload :Http, "action_controller/new_base/http"
autoload :Layouts, "action_controller/new_base/layouts"

View File

@@ -10,6 +10,7 @@ module ActionController
use ActionController::UrlFor
use ActionController::Renderer
use ActionController::Layouts
use ActionController::ConditionalGet
# Legacy modules
include SessionManagement

View File

@@ -0,0 +1,42 @@
module ActionController
module ConditionalGet
# 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>
# * <tt>:last_modified</tt>
# * <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.
#
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]
if options[:public]
cache_control = response.headers["Cache-Control"].split(",").map {|k| k.strip }
cache_control.delete("private")
cache_control.delete("no-cache")
cache_control << "public"
response.headers["Cache-Control"] = cache_control.join(', ')
end
if request.fresh?(response)
head :not_modified
end
end
end
end

View File

@@ -7,6 +7,7 @@ module ActionController
@_response = response
ret = process(request.parameters[:action])
@_response.body = self.response_body
@_response.prepare!
set_test_assigns
ret
end

View File

@@ -0,0 +1,47 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
module Etags
class BasicController < ActionController::Base
self.view_paths = [ActionView::Template::FixturePath.new(
"etags/basic/base.html.erb" => "Hello from without_layout.html.erb",
"layouts/etags.html.erb" => "teh <%= yield %> tagz"
)]
def without_layout
render :action => "base"
end
def with_layout
render :action => "base", :layout => "etag"
end
end
class TestBasic < SimpleRouteCase
describe "Rendering without any special etag options returns an etag that is an MD5 hash of its text"
test "an action without a layout" do
get "/etags/basic/without_layout"
body = "Hello from without_layout.html.erb"
assert_body body
assert_header "Etag", etag_for(body)
assert_status 200
end
test "an action with a layout" do
get "/etags/basic/with_layout"
body = "teh Hello from without_layout.html.erb tagz"
assert_body body
assert_header "Etag", etag_for(body)
assert_status 200
end
def etag_for(text)
%("#{Digest::MD5.hexdigest(text)}")
end
end
end