From 2caf4d5a9337591c2728c7db826526febc5b2158 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 17 Sep 2006 16:20:32 +0000 Subject: Added proper getters and setters for content type and charset [DHH] Added utf-8 as the default charset for all renders. You can change this default using ActionController::Base.default_charset=(encoding) [DHH] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@5129 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- actionpack/CHANGELOG | 11 +++ actionpack/lib/action_controller/base.rb | 16 +++- actionpack/lib/action_controller/caching.rb | 2 +- actionpack/lib/action_controller/rescue.rb | 2 +- actionpack/lib/action_controller/response.rb | 18 ++++ actionpack/lib/action_view/base.rb | 7 +- .../test/controller/action_pack_assertions_test.rb | 6 +- actionpack/test/controller/content_type_test.rb | 99 ++++++++++++++++++++++ actionpack/test/controller/new_render_test.rb | 9 +- .../content_type/render_default_for_rhtml.rhtml | 1 + .../content_type/render_default_for_rxml.rxml | 1 + 11 files changed, 158 insertions(+), 14 deletions(-) create mode 100644 actionpack/test/controller/content_type_test.rb create mode 100644 actionpack/test/fixtures/content_type/render_default_for_rhtml.rhtml create mode 100644 actionpack/test/fixtures/content_type/render_default_for_rxml.rxml diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index ee58588462..f8d4057df5 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,16 @@ *SVN* +* Added utf-8 as the default charset for all renders. You can change this default using ActionController::Base.default_charset=(encoding) [DHH] + +* Added proper getters and setters for content type and charset [DHH]. Example of what we used to do: + + response.headers["Content-Type"] = "application/atom+xml; charset=utf-8" + + ...now: + + response.content_type = Mime::ATOM + response.charset = "utf-8" + * Updated prototype.js to 1.5.0_rc1 with latest fixes. [Rick Olson] - XPATH support diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index c971989582..e9d415085a 100755 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -272,6 +272,10 @@ module ActionController #:nodoc: @@param_parsers = { Mime::XML => :xml_simple } cattr_accessor :param_parsers + # Controls the default charset for all renders. + @@default_charset = "utf-8" + cattr_accessor :default_charset + # Template root determines the base from which template references will be made. So a call to render("test/template") # will be converted to "#{template_root}/test/template.rhtml". class_inheritable_accessor :template_root @@ -420,6 +424,7 @@ module ActionController #:nodoc: log_processing send(method, *arguments) + assign_default_content_type_and_charset response ensure process_cleanup @@ -703,7 +708,7 @@ module ActionController #:nodoc: end if content_type = options[:content_type] - headers["Content-Type"] = content_type.to_s + response.content_type = content_type.to_s end if text = options[:text] @@ -793,12 +798,12 @@ module ActionController #:nodoc: end def render_javascript(javascript, status = nil) #:nodoc: - response.headers['Content-Type'] = 'text/javascript; charset=UTF-8' + response.content_type = Mime::JS render_text(javascript, status) end def render_xml(xml, status = nil) #:nodoc: - response.headers['Content-Type'] = 'application/xml' + response.content_type = Mime::XML render_text(xml, status) end @@ -1034,6 +1039,11 @@ module ActionController #:nodoc: @action_name = (params['action'] || 'index') end + def assign_default_content_type_and_charset + response.content_type ||= Mime::HTML + response.charset ||= self.class.default_charset + end + def action_methods self.class.action_methods end diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb index cc3d9daaa3..491d7d7d0c 100644 --- a/actionpack/lib/action_controller/caching.rb +++ b/actionpack/lib/action_controller/caching.rb @@ -210,7 +210,7 @@ module ActionController #:nodoc: def set_content_type!(action_cache_path) if extention = action_cache_path.extension content_type = Mime::EXTENSION_LOOKUP[extention] - action_cache_path.controller.headers['Content-Type'] = content_type.to_s + action_cache_path.controller.content_type = content_type.to_s end end diff --git a/actionpack/lib/action_controller/rescue.rb b/actionpack/lib/action_controller/rescue.rb index f9b831f18b..b7df9fd125 100644 --- a/actionpack/lib/action_controller/rescue.rb +++ b/actionpack/lib/action_controller/rescue.rb @@ -71,7 +71,7 @@ module ActionController #:nodoc: @template.instance_variable_set("@contents", @template.render_file(template_path_for_local_rescue(exception), false)) - @headers["Content-Type"] = "text/html" + response.content_type = Mime::HTML render_file(rescues_path("layout"), response_code_for_rescue(exception)) end diff --git a/actionpack/lib/action_controller/response.rb b/actionpack/lib/action_controller/response.rb index 2bec477647..d6795e37a0 100755 --- a/actionpack/lib/action_controller/response.rb +++ b/actionpack/lib/action_controller/response.rb @@ -7,6 +7,24 @@ module ActionController @body, @headers, @session, @assigns = "", DEFAULT_HEADERS.merge("cookie" => []), [], [] end + def content_type=(mime_type) + @headers["Content-Type"] = charset ? "#{mime_type}; charset=#{charset}" : mime_type + end + + def content_type + content_type = String(@headers["Content-Type"]).split(";")[0] + content_type.blank? ? nil : content_type + end + + def charset=(encoding) + @headers["Content-Type"] = "#{content_type || "text/html"}; charset=#{encoding}" + end + + def charset + charset = String(@headers["Content-Type"]).split(";")[1] + charset.blank? ? nil : charset.strip.split("=")[1] + end + def redirect(to_url, permanently = false) @headers["Status"] = "302 Found" unless @headers["Status"] == "301 Moved Permanently" @headers["location"] = to_url diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 2f12bdb3c4..5d1bf57c94 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -1,7 +1,6 @@ require 'erb' module ActionView #:nodoc: - class ActionViewError < StandardError #:nodoc: end @@ -441,11 +440,11 @@ module ActionView #:nodoc: if template_requires_setup?(extension) body = case extension.to_sym when :rxml + "@controller.response.content_type ||= 'application/xml'\n" + "xml = Builder::XmlMarkup.new(:indent => 2)\n" + - "@controller.headers['Content-Type'] ||= 'application/xml'\n" + template when :rjs - "@controller.headers['Content-Type'] ||= 'text/javascript'\n" + + "@controller.response.content_type ||= 'text/javascript'\n" + "update_page do |page|\n#{template}\nend" end else @@ -526,4 +525,4 @@ module ActionView #:nodoc: end end -require 'action_view/template_error' +require 'action_view/template_error' \ No newline at end of file diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index a1eea400f2..6e1ccba50e 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -568,18 +568,18 @@ class ActionPackHeaderTest < Test::Unit::TestCase def test_rendering_xml_sets_content_type assert_deprecated(/render/) { process :hello_xml_world } - assert_equal('application/xml', @controller.headers['Content-Type']) + assert_equal('application/xml; charset=utf-8', @controller.headers['Content-Type']) end def test_rendering_xml_respects_content_type @response.headers['Content-Type'] = 'application/pdf' assert_deprecated(/render/) { process :hello_xml_world } - assert_equal('application/pdf', @controller.headers['Content-Type']) + assert_equal('application/pdf; charset=utf-8', @controller.headers['Content-Type']) end def test_render_text_with_custom_content_type get :render_text_with_custom_content_type - assert_equal 'application/rss+xml', @response.headers['Content-Type'] + assert_equal 'application/rss+xml; charset=utf-8', @response.headers['Content-Type'] end end diff --git a/actionpack/test/controller/content_type_test.rb b/actionpack/test/controller/content_type_test.rb new file mode 100644 index 0000000000..71563ba9a6 --- /dev/null +++ b/actionpack/test/controller/content_type_test.rb @@ -0,0 +1,99 @@ +require File.dirname(__FILE__) + '/../abstract_unit' + +class ContentTypeController < ActionController::Base + def render_content_type_from_body + response.content_type = Mime::RSS + render :text => "hello world!" + end + + def render_defaults + render :text => "hello world!" + end + + def render_content_type_from_render + render :text => "hello world!", :content_type => Mime::RSS + end + + def render_charset_from_body + response.charset = "utf-16" + render :text => "hello world!" + end + + def render_default_for_rhtml + end + + def render_default_for_rxml + end + + def render_change_for_rxml + response.content_type = Mime::HTML + render :action => "render_default_for_rxml" + end + + def rescue_action(e) raise end +end + +ContentTypeController.template_root = File.dirname(__FILE__) + "/../fixtures/" + +class ContentTypeTest < Test::Unit::TestCase + def setup + @controller = ContentTypeController.new + + # enable a logger so that (e.g.) the benchmarking stuff runs, so we can get + # a more accurate simulation of what happens in "real life". + @controller.logger = Logger.new(nil) + + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + def test_render_defaults + get :render_defaults + assert_equal "utf-8", @response.charset + assert_equal Mime::HTML, @response.content_type + end + + def test_render_changed_charset_default + ContentTypeController.default_charset = "utf-16" + get :render_defaults + assert_equal "utf-16", @response.charset + assert_equal Mime::HTML, @response.content_type + ContentTypeController.default_charset = "utf-8" + end + + def test_content_type_from_body + get :render_content_type_from_body + assert_equal "application/rss+xml", @response.content_type + assert_equal "utf-8", @response.charset + end + + def test_content_type_from_render + get :render_content_type_from_render + assert_equal "application/rss+xml", @response.content_type + assert_equal "utf-8", @response.charset + end + + def test_charset_from_body + get :render_charset_from_body + assert_equal "utf-16", @response.charset + assert_equal Mime::HTML, @response.content_type + end + + def test_default_for_rhtml + get :render_default_for_rhtml + assert_equal Mime::HTML, @response.content_type + assert_equal "utf-8", @response.charset + end + + def test_default_for_rxml + get :render_default_for_rxml + assert_equal Mime::XML, @response.content_type + assert_equal "utf-8", @response.charset + end + + def test_change_for_rxml + get :render_change_for_rxml + assert_equal Mime::HTML, @response.content_type + assert_equal "utf-8", @response.charset + end +end \ No newline at end of file diff --git a/actionpack/test/controller/new_render_test.rb b/actionpack/test/controller/new_render_test.rb index e06b657b07..8af6440c56 100644 --- a/actionpack/test/controller/new_render_test.rb +++ b/actionpack/test/controller/new_render_test.rb @@ -263,6 +263,11 @@ class NewRenderTestController < ActionController::Base render :action => "content_for", :layout => "yield" end + def render_content_type_from_body + response.content_type = Mime::RSS + render :text => "hello world!" + end + def rescue_action(e) raise end private @@ -572,14 +577,14 @@ EOS def test_update_page get :update_page assert_template nil - assert_equal 'text/javascript; charset=UTF-8', @response.headers['Content-Type'] + assert_equal 'text/javascript; charset=utf-8', @response.headers['Content-Type'] assert_equal 2, @response.body.split($/).length end def test_update_page_with_instance_variables get :update_page_with_instance_variables assert_template nil - assert_equal 'text/javascript; charset=UTF-8', @response.headers['Content-Type'] + assert_equal 'text/javascript; charset=utf-8', @response.headers['Content-Type'] assert_match /balance/, @response.body assert_match /\$37/, @response.body end diff --git a/actionpack/test/fixtures/content_type/render_default_for_rhtml.rhtml b/actionpack/test/fixtures/content_type/render_default_for_rhtml.rhtml new file mode 100644 index 0000000000..c7926d48bb --- /dev/null +++ b/actionpack/test/fixtures/content_type/render_default_for_rhtml.rhtml @@ -0,0 +1 @@ +<%= 'hello world!' %> \ No newline at end of file diff --git a/actionpack/test/fixtures/content_type/render_default_for_rxml.rxml b/actionpack/test/fixtures/content_type/render_default_for_rxml.rxml new file mode 100644 index 0000000000..598d62e2fc --- /dev/null +++ b/actionpack/test/fixtures/content_type/render_default_for_rxml.rxml @@ -0,0 +1 @@ +xml.p "Hello world!" \ No newline at end of file -- cgit v1.2.3