Skip to content
Browse files

Add ActionController::Base#head for rendering empty responses. Add su…

…pport for symbolic status codes, as well as for having raw integer statuses expand with their default messages.

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@5199 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
1 parent d6925b1 commit b2ede64a89a5837a047e75f21a1522324a614514 @jamis jamis committed Sep 28, 2006
View
11 actionpack/CHANGELOG
@@ -1,5 +1,16 @@
*SVN*
+* Make the :status parameter expand to the default message for that status code if it is an integer. Also support symbol statuses. [Jamis Buck]. Examples:
+
+ head :status => 404 # expands to "404 Not Found"
+ head :status => :not_found # expands to "404 Not Found"
+ head :status => :created # expands to "201 Created"
+
+* Add head(options = {}) for responses that have no body. [Jamis Buck]. Examples:
+
+ head :status => 404 # return an empty response with a 404 status
+ head :location => person_path(@person), :status => 201
+
* Fix bug that kept any before_filter except the first one from being able to halt the before_filter chain. [Rick Olson]
* strip_links is case-insensitive. #6285 [tagoh, Bob Silva]
View
27 actionpack/lib/action_controller/base.rb
@@ -4,6 +4,7 @@
require 'action_controller/routing'
require 'action_controller/resources'
require 'action_controller/url_rewriter'
+require 'action_controller/status_codes'
require 'drb'
require 'set'
@@ -209,6 +210,7 @@ class Base
DEFAULT_RENDER_STATUS_CODE = "200 OK"
include Reloadable::Deprecated
+ include StatusCodes
# Determines whether the view has access to controller internals @request, @response, @session, and @template.
# By default, it does.
@@ -793,7 +795,7 @@ def render_template(template, status = nil, type = :rhtml, local_assigns = {}) #
def render_text(text = nil, status = nil) #:nodoc:
@performed_render = true
- response.headers['Status'] = (status || DEFAULT_RENDER_STATUS_CODE).to_s
+ response.headers['Status'] = interpret_status(status || DEFAULT_RENDER_STATUS_CODE)
response.body = text
end
@@ -830,6 +832,29 @@ def render_without_layout(template_name = default_template_name, status = nil) #
end
+ # Return a response that has no content (merely headers). The options
+ # argument is interpreted to be a hash of header names and values.
+ # This allows you to easily return a response that consists only of
+ # significant headers:
+ #
+ # head :status => :created, :location => person_path(@person)
+ #
+ # It can also be used to return exceptional conditions:
+ #
+ # return head(:status => :method_not_allowed) unless request.post?
+ # return head(:status => :bad_request) unless valid_request?
+ # render
+ def head(options = {})
+ status = interpret_status(options.delete(:status) || :ok)
+
+ options.each do |key, value|
+ headers[key.to_s.dasherize.split(/-/).map { |v| v.capitalize }.join("-")] = value.to_s
+ end
+
+ render :nothing => true, :status => status
+ end
+
+
# Clears the rendered results, allowing for another render to be performed.
def erase_render_results #:nodoc:
response.body = nil
View
79 actionpack/lib/action_controller/status_codes.rb
@@ -0,0 +1,79 @@
+module ActionController
+ module StatusCodes
+
+ # Defines the standard HTTP status codes, by integer, with their
+ # corresponding default message texts.
+ STATUS_CODES = {
+ 100 => "Continue",
+ 101 => "Switching Protocols",
+
+ 200 => "OK",
+ 201 => "Created",
+ 202 => "Accepted",
+ 203 => "Non-Authoritative Information",
+ 204 => "No Content",
+ 205 => "Reset Content",
+ 206 => "Partial Content",
+
+ 300 => "Multiple Choices",
+ 301 => "Moved Permanently",
+ 302 => "Found",
+ 303 => "See Other",
+ 304 => "Not Modified",
+ 305 => "Use Proxy",
+ 307 => "Temporary Redirect",
+
+ 400 => "Bad Request",
+ 401 => "Unauthorized",
+ 402 => "Payment Required",
+ 403 => "Forbidden",
+ 404 => "Not Found",
+ 405 => "Method Not Allowed",
+ 406 => "Not Acceptable",
+ 407 => "Proxy Authentication Required",
+ 408 => "Request Timeout",
+ 409 => "Conflict",
+ 410 => "Gone",
+ 411 => "Length Required",
+ 412 => "Precondition Failed",
+ 413 => "Request Entity Too Large",
+ 414 => "Request-URI Too Long",
+ 415 => "Unsupported Media Type",
+ 416 => "Requested Range Not Satisfiable",
+ 417 => "Expectation Failed",
+
+ 500 => "Internal Server Error",
+ 501 => "Not Implemented",
+ 502 => "Bad Gateway",
+ 503 => "Service Unavailable",
+ 504 => "Gateway Timeout",
+ 505 => "HTTP Version Not Supported"
+ }
+
+ # Provides a symbol-to-fixnum lookup for converting a symbol (like
+ # :created or :not_implemented) into its corresponding HTTP status
+ # code (like 200 or 501).
+ SYMBOL_TO_STATUS_CODE = STATUS_CODES.inject({}) do |hash, (code, message)|
+ hash[message.gsub(/ /, "").underscore.to_sym] = code
+ hash
+ end
+
+ # Given a status parameter, determine whether it needs to be converted
+ # to a string. If it is a fixnum, use the STATUS_CODES hash to lookup
+ # the default message. If it is a symbol, use the SYMBOL_TO_STATUS_CODE
+ # hash to convert it.
+ def interpret_status(status)
+ case status
+ when Fixnum then
+ "#{status} #{STATUS_CODES[status]}".strip
+ when Symbol then
+ interpret_status(SYMBOL_TO_STATUS_CODE[status] ||
+ "500 Unknown Status #{status.inspect}")
+ else
+ status.to_s
+ end
+ end
+ private :interpret_status
+
+ end
+end
View
59 actionpack/test/controller/new_render_test.rb
@@ -202,6 +202,26 @@ def hello_world_from_rxml_using_template
render :template => "test/hello_world.rxml"
end
+ def head_with_location_header
+ head :location => "/foo"
+ end
+
+ def head_with_symbolic_status
+ head :status => params[:status].intern
+ end
+
+ def head_with_integer_status
+ head :status => params[:status].to_i
+ end
+
+ def head_with_string_status
+ head :status => params[:status]
+ end
+
+ def head_with_custom_header
+ head :x_custom_header => "something"
+ end
+
helper NewRenderTestHelper
helper do
def rjs_helper_method(value)
@@ -602,4 +622,43 @@ def test_overwritting_rendering_relative_file_with_extension
get :hello_world_from_rxml_using_action
assert_equal "<html>\n <p>Hello</p>\n</html>\n", @response.body
end
+
+
+ def test_head_with_location_header
+ get :head_with_location_header
+ assert @response.body.blank?
+ assert_equal "/foo", @response.headers["Location"]
+ end
+
+ def test_head_with_custom_header
+ get :head_with_custom_header
+ assert @response.body.blank?
+ assert_equal "something", @response.headers["X-Custom-Header"]
+ end
+
+ def test_head_with_symbolic_status
+ get :head_with_symbolic_status, :status => "ok"
+ assert_equal "200 OK", @response.headers["Status"]
+
+ get :head_with_symbolic_status, :status => "not_found"
+ assert_equal "404 Not Found", @response.headers["Status"]
+
+ ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE.each do |status, code|
+ get :head_with_symbolic_status, :status => status.to_s
+ assert_equal code, @response.response_code
+ end
+ end
+
+ def test_head_with_integer_status
+ ActionController::StatusCodes::STATUS_CODES.each do |code, message|
+ get :head_with_integer_status, :status => code.to_s
+ assert_equal message, @response.message
+ end
+ end
+
+ def head_with_string_status
+ get :head_with_string_status, :status => "404 Eat Dirt"
+ assert_equal 404, @response.response_code
+ assert_equal "Eat Dirt", @response.message
+ end
end
View
2 actionpack/test/controller/send_file_test.rb
@@ -97,7 +97,7 @@ def test_send_file_headers!
define_method "test_send_#{method}_status" do
@controller.options = { :stream => false, :status => 500 }
assert_nothing_raised { assert_not_nil process(method) }
- assert_equal '500', @controller.headers['Status']
+ assert_equal '500 Internal Server Error', @controller.headers['Status']
end
define_method "test_default_send_#{method}_status" do

0 comments on commit b2ede64

Please sign in to comment.
Something went wrong with that request. Please try again.