提交 bd8c0b8a 编写于 作者: S Santiago Pastorino

Return proper format on exceptions

上级 174f36a0
## Rails 4.0.0 (unreleased) ## ## Rails 4.0.0 (unreleased) ##
* Return proper format on exceptions. *Santiago Pastorino*
* Allow to use mounted_helpers (helpers for accessing mounted engines) in ActionView::TestCase. *Piotr Sarnacki* * Allow to use mounted_helpers (helpers for accessing mounted engines) in ActionView::TestCase. *Piotr Sarnacki*
* Include mounted_helpers (helpers for accessing mounted engines) in ActionDispatch::IntegrationTest by default. *Piotr Sarnacki* * Include mounted_helpers (helpers for accessing mounted engines) in ActionDispatch::IntegrationTest by default. *Piotr Sarnacki*
......
...@@ -3,28 +3,50 @@ module ActionDispatch ...@@ -3,28 +3,50 @@ module ActionDispatch
class PublicExceptions class PublicExceptions
attr_accessor :public_path attr_accessor :public_path
def initialize(public_path) def initialize(public_path, consider_all_requests_local = false)
@public_path = public_path @public_path = public_path
@consider_all_requests_local = consider_all_requests_local
end end
def call(env) def call(env)
status = env["PATH_INFO"][1..-1] exception = env["action_dispatch.exception"]
locale_path = "#{public_path}/#{status}.#{I18n.locale}.html" if I18n.locale status = env["PATH_INFO"][1..-1]
path = "#{public_path}/#{status}.html" request = ActionDispatch::Request.new(env)
content_type = request.formats.first
if locale_path && File.exist?(locale_path) format = (mime = Mime[content_type]) && "to_#{mime.to_sym}"
render(status, File.read(locale_path)) body = { :status => status, :error => exception.message }
elsif File.exist?(path)
render(status, File.read(path)) render(status, body, :format => format, :content_type => content_type)
end
private
def render(status, body, options)
format = options[:format]
if !@consider_all_requests_local && format && body.respond_to?(format)
render_format(status, body.public_send(format), options)
else else
[404, { "X-Cascade" => "pass" }, []] render_html(status)
end end
end end
private def render_format(status, body, options)
[status, {'Content-Type' => "#{options[:content_type]}; charset=#{ActionDispatch::Response.default_charset}",
'Content-Length' => body.bytesize.to_s}, [body]]
end
def render_html(status)
found = false
path = "#{public_path}/#{status}.#{I18n.locale}.html" if I18n.locale
path = "#{public_path}/#{status}.html" unless path && (found = File.exist?(path))
def render(status, body) if found || File.exist?(path)
[status, {'Content-Type' => "text/html; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]] body = File.read(path)
[status, {'Content-Type' => "text/html; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]]
else
[404, { "X-Cascade" => "pass" }, []]
end
end end
end end
end end
\ No newline at end of file
...@@ -22,6 +22,14 @@ def show_detailed_exceptions? ...@@ -22,6 +22,14 @@ def show_detailed_exceptions?
end end
end end
class ShowLocalExceptionsController < ActionController::Base
use ActionDispatch::ShowExceptions, ActionDispatch::PublicExceptions.new("#{FIXTURE_LOAD_PATH}/public", true)
def boom
raise 'boom!'
end
end
class ShowExceptionsTest < ActionDispatch::IntegrationTest class ShowExceptionsTest < ActionDispatch::IntegrationTest
test 'show error page from a remote ip' do test 'show error page from a remote ip' do
@app = ShowExceptionsController.action(:boom) @app = ShowExceptionsController.action(:boom)
...@@ -68,4 +76,39 @@ class ShowExceptionsOverridenTest < ActionDispatch::IntegrationTest ...@@ -68,4 +76,39 @@ class ShowExceptionsOverridenTest < ActionDispatch::IntegrationTest
assert_match(/boom/, body) assert_match(/boom/, body)
end end
end end
class ShowExceptionsFormatsTest < ActionDispatch::IntegrationTest
def test_render_json_exception
@app = ShowExceptionsOverridenController.action(:boom)
get "/", {}, 'HTTP_ACCEPT' => 'application/json'
assert_response :internal_server_error
assert_equal 'application/json', response.content_type.to_s
assert_equal({ :status => '500', :error => 'boom!' }.to_json, response.body)
end
def test_render_xml_exception
@app = ShowExceptionsOverridenController.action(:boom)
get "/", {}, 'HTTP_ACCEPT' => 'application/xml'
assert_response :internal_server_error
assert_equal 'application/xml', response.content_type.to_s
assert_equal({ :status => '500', :error => 'boom!' }.to_xml, response.body)
end
def test_render_fallback_exception
@app = ShowExceptionsOverridenController.action(:boom)
get "/", {}, 'HTTP_ACCEPT' => 'text/csv'
assert_response :internal_server_error
assert_equal 'text/html', response.content_type.to_s
end
end
class ShowExceptionsFormatsTest < ActionDispatch::IntegrationTest
def test_render_formatted_exception_in_development
@app = ShowLocalExceptionsController.action(:boom)
get "/", {}, 'HTTP_ACCEPT' => 'application/xml'
assert_response :internal_server_error
assert_equal 'text/html', response.content_type.to_s
end
end
end end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册