aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG.md6
-rw-r--r--actionpack/actionpack.gemspec2
-rw-r--r--actionpack/lib/action_controller/metal/rescue.rb17
-rw-r--r--actionpack/lib/action_controller/railtie.rb2
-rw-r--r--actionpack/lib/action_dispatch.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/closed_error.rb7
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb10
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_exceptions.rb3
-rw-r--r--actionpack/lib/action_dispatch/middleware/flash.rb6
-rw-r--r--actionpack/lib/action_dispatch/middleware/public_exceptions.rb30
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/abstract_store.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/show_exceptions.rb65
-rw-r--r--actionpack/lib/action_dispatch/routing.rb1
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb14
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb3
-rw-r--r--actionpack/lib/action_view/lookup_context.rb5
-rw-r--r--actionpack/test/abstract_unit.rb10
-rw-r--r--actionpack/test/controller/default_url_options_with_filter_test.rb2
-rw-r--r--actionpack/test/controller/flash_test.rb40
-rw-r--r--actionpack/test/controller/new_base/render_template_test.rb6
-rw-r--r--actionpack/test/controller/show_exceptions_test.rb21
-rw-r--r--actionpack/test/controller/url_for_test.rb8
-rw-r--r--actionpack/test/dispatch/cookies_test.rb98
-rw-r--r--actionpack/test/dispatch/debug_exceptions_test.rb27
-rw-r--r--actionpack/test/dispatch/routing_test.rb1
-rw-r--r--actionpack/test/dispatch/show_exceptions_test.rb28
-rw-r--r--actionpack/test/template/compiled_templates_test.rb4
-rw-r--r--actionpack/test/template/date_helper_test.rb19
-rw-r--r--actionpack/test/template/lookup_context_test.rb8
30 files changed, 207 insertions, 244 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index b354f05960..b753addef4 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,5 +1,7 @@
## Rails 3.2.0 (unreleased) ##
+* The ShowExceptions middleware now accepts a exceptions application that is responsible to render an exception when the application fails. The application is invoked with a copy of the exception in `env["action_dispatch.exception"]` and with the PATH_INFO rewritten to the status code. *José Valim*
+
* Add `button_tag` support to ActionView::Helpers::FormBuilder.
This support mimics the default behavior of `submit_tag`.
@@ -68,9 +70,9 @@
<%= f.text_field :version %>
<% end %>
-* Refactor ActionDispatch::ShowExceptions. Controller is responsible for choice to show exceptions. *Sergey Nartimov*
+* Refactor ActionDispatch::ShowExceptions. The controller is responsible for choosing to show exceptions when `consider_all_requests_local` is false.
- It's possible to override +show_detailed_exceptions?+ in controllers to specify which requests should provide debugging information on errors.
+ It's possible to override `show_detailed_exceptions?` in controllers to specify which requests should provide debugging information on errors. The default value is now false, meaning local requests in production will no longer show the detailed exceptions page unless `show_detailed_exceptions?` is overridden and set to `request.local?`.
* Responders now return 204 No Content for API requests without a response body (as in the new scaffold) *José Valim*
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index d6e9519915..1aa346929e 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
s.add_dependency('i18n', '~> 0.6')
s.add_dependency('rack', '~> 1.3.5')
s.add_dependency('rack-test', '~> 0.6.1')
- s.add_dependency('journey', '~> 1.0.0')
+ s.add_dependency('journey', '~> 1.0.0.rc1')
s.add_dependency('sprockets', '~> 2.1.2')
s.add_dependency('erubis', '~> 2.7.0')
diff --git a/actionpack/lib/action_controller/metal/rescue.rb b/actionpack/lib/action_controller/metal/rescue.rb
index 736ff5b31c..68cc9a9c9b 100644
--- a/actionpack/lib/action_controller/metal/rescue.rb
+++ b/actionpack/lib/action_controller/metal/rescue.rb
@@ -1,13 +1,11 @@
module ActionController #:nodoc:
+ # This module is responsible to provide `rescue_from` helpers
+ # to controllers and configure when detailed exceptions must be
+ # shown.
module Rescue
extend ActiveSupport::Concern
include ActiveSupport::Rescuable
- included do
- config_accessor :consider_all_requests_local
- self.consider_all_requests_local = false if consider_all_requests_local.nil?
- end
-
def rescue_with_handler(exception)
if (exception.respond_to?(:original_exception) &&
(orig_exception = exception.original_exception) &&
@@ -17,15 +15,20 @@ module ActionController #:nodoc:
super(exception)
end
+ # Override this method if you want to customize when detailed
+ # exceptions must be shown. This method is only called when
+ # consider_all_requests_local is false. By default, it returns
+ # false, but someone may set it to `request.local?` so local
+ # requests in production still shows the detailed exception pages.
def show_detailed_exceptions?
- consider_all_requests_local || request.local?
+ false
end
private
def process_action(*args)
super
rescue Exception => exception
- request.env['action_dispatch.show_detailed_exceptions'] = show_detailed_exceptions?
+ request.env['action_dispatch.show_detailed_exceptions'] ||= show_detailed_exceptions?
rescue_with_handler(exception) || raise(exception)
end
end
diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb
index cb2e2b17aa..7af256fd99 100644
--- a/actionpack/lib/action_controller/railtie.rb
+++ b/actionpack/lib/action_controller/railtie.rb
@@ -21,8 +21,6 @@ module ActionController
paths = app.config.paths
options = app.config.action_controller
- options.consider_all_requests_local ||= app.config.consider_all_requests_local
-
options.assets_dir ||= paths["public"].first
options.javascripts_dir ||= paths["public/javascripts"].first
options.stylesheets_dir ||= paths["public/stylesheets"].first
diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb
index 89f515ee3d..4b821037dc 100644
--- a/actionpack/lib/action_dispatch.rb
+++ b/actionpack/lib/action_dispatch.rb
@@ -56,6 +56,7 @@ module ActionDispatch
autoload :Flash
autoload :Head
autoload :ParamsParser
+ autoload :PublicExceptions
autoload :Reloader
autoload :RemoteIp
autoload :Rescue
@@ -63,7 +64,6 @@ module ActionDispatch
autoload :Static
end
- autoload :ClosedError, 'action_dispatch/middleware/closed_error'
autoload :MiddlewareStack, 'action_dispatch/middleware/stack'
autoload :Routing
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index 129a8b1031..64459836b5 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -70,7 +70,7 @@ module ActionDispatch
host = ""
unless options[:subdomain] == false
- host << (options[:subdomain] || extract_subdomain(options[:host], tld_length))
+ host << (options[:subdomain] || extract_subdomain(options[:host], tld_length)).to_param
host << "."
end
host << (options[:domain] || extract_domain(options[:host], tld_length))
diff --git a/actionpack/lib/action_dispatch/middleware/closed_error.rb b/actionpack/lib/action_dispatch/middleware/closed_error.rb
deleted file mode 100644
index 0a4db47f4b..0000000000
--- a/actionpack/lib/action_dispatch/middleware/closed_error.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-module ActionDispatch
- class ClosedError < StandardError #:nodoc:
- def initialize(kind)
- super "Cannot modify #{kind} because it was closed. This means it was already streamed back to the client or converted to HTTP headers."
- end
- end
-end
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index 51cec41a34..39ff58a447 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -121,10 +121,6 @@ module ActionDispatch
@cookies = {}
end
- attr_reader :closed
- alias :closed? :closed
- def close!; @closed = true end
-
def each(&block)
@cookies.each(&block)
end
@@ -165,7 +161,6 @@ module ActionDispatch
# Sets the cookie named +name+. The second argument may be the very cookie
# value, or a hash of options as documented above.
def []=(key, options)
- raise ClosedError, :cookies if closed?
if options.is_a?(Hash)
options.symbolize_keys!
value = options[:value]
@@ -259,7 +254,6 @@ module ActionDispatch
end
def []=(key, options)
- raise ClosedError, :cookies if closed?
if options.is_a?(Hash)
options.symbolize_keys!
else
@@ -298,7 +292,6 @@ module ActionDispatch
end
def []=(key, options)
- raise ClosedError, :cookies if closed?
if options.is_a?(Hash)
options.symbolize_keys!
options[:value] = @verifier.generate(options[:value])
@@ -352,9 +345,6 @@ module ActionDispatch
end
[status, headers, body]
- ensure
- cookie_jar = ActionDispatch::Request.new(env).cookie_jar unless cookie_jar
- cookie_jar.close!
end
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
index cd4af82c6e..dabbabb1e6 100644
--- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
@@ -15,8 +15,9 @@ module ActionDispatch
begin
response = @app.call(env)
- # TODO: Maybe this should be in the router itself
if response[1]['X-Cascade'] == 'pass'
+ body = response[2]
+ body.close if body.respond_to?(:close)
raise ActionController::RoutingError, "No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}"
end
rescue Exception => exception
diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb
index e59404ef68..bc5b163931 100644
--- a/actionpack/lib/action_dispatch/middleware/flash.rb
+++ b/actionpack/lib/action_dispatch/middleware/flash.rb
@@ -93,7 +93,6 @@ module ActionDispatch
end
def []=(k, v) #:nodoc:
- raise ClosedError, :flash if closed?
keep(k)
@flashes[k] = v
end
@@ -159,10 +158,6 @@ module ActionDispatch
@now ||= FlashNow.new(self)
end
- attr_reader :closed
- alias :closed? :closed
- def close!; @closed = true; end
-
# Keeps either the entire current flash or a specific flash entry available for the next action:
#
# flash.keep # keeps the entire flash
@@ -258,7 +253,6 @@ module ActionDispatch
end
env[KEY] = new_hash
- new_hash.close!
end
if session.key?('flash') && session['flash'].empty?
diff --git a/actionpack/lib/action_dispatch/middleware/public_exceptions.rb b/actionpack/lib/action_dispatch/middleware/public_exceptions.rb
new file mode 100644
index 0000000000..85b8d178bf
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/public_exceptions.rb
@@ -0,0 +1,30 @@
+module ActionDispatch
+ # A simple Rack application that renders exceptions in the given public path.
+ class PublicExceptions
+ attr_accessor :public_path
+
+ def initialize(public_path)
+ @public_path = public_path
+ end
+
+ def call(env)
+ status = env["PATH_INFO"][1..-1]
+ locale_path = "#{public_path}/#{status}.#{I18n.locale}.html" if I18n.locale
+ path = "#{public_path}/#{status}.html"
+
+ if locale_path && File.exist?(locale_path)
+ render(status, File.read(locale_path))
+ elsif File.exist?(path)
+ render(status, File.read(path))
+ else
+ [404, { "X-Cascade" => "pass" }, []]
+ end
+ end
+
+ private
+
+ def render(status, body)
+ [status, {'Content-Type' => "text/html; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]]
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
index 6bcf099d2c..f75b4d4d04 100644
--- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
@@ -74,10 +74,6 @@ module ActionDispatch
class AbstractStore < Rack::Session::Abstract::ID
include Compatibility
include StaleSessionCheck
-
- def destroy_session(env, sid, options)
- raise '#destroy_session needs to be implemented.'
- end
end
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
index 0c95248611..5eceeece1f 100644
--- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
@@ -4,10 +4,18 @@ require 'active_support/deprecation'
module ActionDispatch
# This middleware rescues any exception returned by the application
- # and wraps them in a format for the end user.
+ # and calls an exceptions app that will wrap it in a format for the end user.
+ #
+ # The exceptions app should be passed as parameter on initialization
+ # of ShowExceptions. Everytime there is an exception, ShowExceptions will
+ # store the exception in env["action_dispatch.exception"], rewrite the
+ # PATH_INFO to the exception status code and call the rack app.
+ #
+ # If the application returns a "X-Cascade" pass response, this middleware
+ # will send an empty response as result with the correct status code.
+ # If any exception happens inside the exceptions app, this middleware
+ # catches the exceptions and returns a FAILSAFE_RESPONSE.
class ShowExceptions
- RESCUES_TEMPLATE_PATH = File.join(File.dirname(__FILE__), 'templates')
-
FAILSAFE_RESPONSE = [500, {'Content-Type' => 'text/html'},
["<html><body><h1>500 Internal Server Error</h1>" <<
"If you are the administrator of this website, then please read this web " <<
@@ -28,9 +36,19 @@ module ActionDispatch
end
end
- def initialize(app, consider_all_requests_local = nil)
- ActiveSupport::Deprecation.warn "Passing consider_all_requests_local option to ActionDispatch::ShowExceptions middleware no longer works" unless consider_all_requests_local.nil?
+ def initialize(app, exceptions_app = nil)
+ if [true, false].include?(exceptions_app)
+ ActiveSupport::Deprecation.warn "Passing consider_all_requests_local option to ActionDispatch::ShowExceptions middleware no longer works"
+ exceptions_app = nil
+ end
+
+ if exceptions_app.nil?
+ raise ArgumentError, "You need to pass an exceptions_app when initializing ActionDispatch::ShowExceptions. " \
+ "In case you want to render pages from a public path, you can use ActionDispatch::PublicExceptions.new('path/to/public')"
+ end
+
@app = app
+ @exceptions_app = exceptions_app
end
def call(env)
@@ -40,7 +58,7 @@ module ActionDispatch
raise exception if env['action_dispatch.show_exceptions'] == false
end
- response || render_exception_with_failsafe(env, exception)
+ response || render_exception(env, exception)
end
private
@@ -50,37 +68,20 @@ module ActionDispatch
def status_code(*)
end
- def render_exception_with_failsafe(env, exception)
- render_exception(env, exception)
+ def render_exception(env, exception)
+ wrapper = ExceptionWrapper.new(env, exception)
+ status = wrapper.status_code
+ env["action_dispatch.exception"] = wrapper.exception
+ env["PATH_INFO"] = "/#{status}"
+ response = @exceptions_app.call(env)
+ response[1]['X-Cascade'] == 'pass' ? pass_response(status) : response
rescue Exception => failsafe_error
$stderr.puts "Error during failsafe response: #{failsafe_error}\n #{failsafe_error.backtrace * "\n "}"
FAILSAFE_RESPONSE
end
- def render_exception(env, exception)
- wrapper = ExceptionWrapper.new(env, exception)
-
- status = wrapper.status_code
- locale_path = "#{public_path}/#{status}.#{I18n.locale}.html" if I18n.locale
- path = "#{public_path}/#{status}.html"
-
- if locale_path && File.exist?(locale_path)
- render(status, File.read(locale_path))
- elsif File.exist?(path)
- render(status, File.read(path))
- else
- render(status, '')
- end
- end
-
- def render(status, body)
- [status, {'Content-Type' => "text/html; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]]
- end
-
- # TODO: Make this a middleware initialization parameter once
- # we removed the second option (which is deprecated)
- def public_path
- defined?(Rails.public_path) ? Rails.public_path : 'public_path'
+ def pass_response(status)
+ [status, {"Content-Type" => "text/html; charset=#{Response.default_charset}", "Content-Length" => "0"}, []]
end
end
end
diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb
index 1dcd83ceb5..fa300b4a16 100644
--- a/actionpack/lib/action_dispatch/routing.rb
+++ b/actionpack/lib/action_dispatch/routing.rb
@@ -277,7 +277,6 @@ module ActionDispatch
#
module Routing
autoload :Mapper, 'action_dispatch/routing/mapper'
- autoload :Route, 'action_dispatch/routing/route'
autoload :RouteSet, 'action_dispatch/routing/route_set'
autoload :RoutesProxy, 'action_dispatch/routing/routes_proxy'
autoload :UrlFor, 'action_dispatch/routing/url_for'
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 88e422c05d..4d83c6dee1 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -1286,7 +1286,7 @@ module ActionDispatch
action = nil
end
- if !options.fetch(:as) { true }
+ if !options.fetch(:as, true)
options.delete(:as)
else
options[:as] = name_for_action(options[:as], action)
@@ -1472,8 +1472,16 @@ module ActionDispatch
[name_prefix, member_name, prefix]
end
- candidate = name.select(&:present?).join("_").presence
- candidate unless as.nil? && @set.routes.find { |r| r.name == candidate }
+ if candidate = name.select(&:present?).join("_").presence
+ # If a name was not explicitly given, we check if it is valid
+ # and return nil in case it isn't. Otherwise, we pass the invalid name
+ # forward so the underlying router engine treats it and raises an exception.
+ if as.nil?
+ candidate unless @set.routes.find { |r| r.name == candidate } || candidate !~ /\A[_a-z]/i
+ else
+ candidate
+ end
+ end
end
end
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index 38cf922ef4..dd2b59cb0a 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -947,8 +947,9 @@ module ActionView
# and join them with their appropriate separators.
def build_selects_from_types(order)
select = ''
+ first_visible = order.find { |type| !@options[:"discard_#{type}"] }
order.reverse.each do |type|
- separator = separator(type) unless type == order.first # don't add on last field
+ separator = separator(type) unless type == first_visible # don't add before first visible field
select.insert(0, separator.to_s + send("select_#{type}").to_s)
end
select.html_safe
diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb
index 95478b9af6..3bb2b98e48 100644
--- a/actionpack/lib/action_view/lookup_context.rb
+++ b/actionpack/lib/action_view/lookup_context.rb
@@ -59,6 +59,10 @@ module ActionView
@details_keys[details] ||= new
end
+ def self.clear
+ @details_keys.clear
+ end
+
def initialize
@hash = object_hash
end
@@ -85,6 +89,7 @@ module ActionView
protected
def _set_detail(key, value)
+ @details = @details.dup if @details_key
@details_key = nil
@details[key] = value
end
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index c95b8221a1..40ca23a39d 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -174,7 +174,7 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
def self.build_app(routes = nil)
RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
- middleware.use "ActionDispatch::ShowExceptions"
+ middleware.use "ActionDispatch::ShowExceptions", ActionDispatch::PublicExceptions.new("#{FIXTURE_LOAD_PATH}/public")
middleware.use "ActionDispatch::DebugExceptions"
middleware.use "ActionDispatch::Callbacks"
middleware.use "ActionDispatch::ParamsParser"
@@ -337,14 +337,6 @@ class Workshop
end
module ActionDispatch
- class ShowExceptions
- private
- remove_method :public_path
- def public_path
- "#{FIXTURE_LOAD_PATH}/public"
- end
- end
-
class DebugExceptions
private
remove_method :stderr_logger
diff --git a/actionpack/test/controller/default_url_options_with_filter_test.rb b/actionpack/test/controller/default_url_options_with_filter_test.rb
index 3bbb981040..ef028e8cdb 100644
--- a/actionpack/test/controller/default_url_options_with_filter_test.rb
+++ b/actionpack/test/controller/default_url_options_with_filter_test.rb
@@ -21,7 +21,7 @@ end
class ControllerWithBeforeFilterAndDefaultUrlOptionsTest < ActionController::TestCase
- # This test has it´s roots in issue #1872
+ # This test has its roots in issue #1872
test "should redirect with correct locale :de" do
get :redirect, :locale => "de"
assert_redirected_to "/controller_with_before_filter_and_default_url_options/target?locale=de"
diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb
index e19612eace..d497913dc4 100644
--- a/actionpack/test/controller/flash_test.rb
+++ b/actionpack/test/controller/flash_test.rb
@@ -254,16 +254,6 @@ class FlashIntegrationTest < ActionDispatch::IntegrationTest
end
end
- def test_setting_flash_raises_after_stream_back_to_client
- with_test_route_set do
- env = { 'action_dispatch.request.flash_hash' => ActionDispatch::Flash::FlashHash.new }
- get '/set_flash', nil, env
- assert_raise(ActionDispatch::ClosedError) {
- @request.flash['alert'] = 'alert'
- }
- end
- end
-
def test_setting_flash_does_not_raise_in_following_requests
with_test_route_set do
env = { 'action_dispatch.request.flash_hash' => ActionDispatch::Flash::FlashHash.new }
@@ -280,36 +270,6 @@ class FlashIntegrationTest < ActionDispatch::IntegrationTest
end
end
- def test_setting_flash_raises_after_stream_back_to_client_even_with_an_empty_flash
- with_test_route_set do
- env = { 'action_dispatch.request.flash_hash' => ActionDispatch::Flash::FlashHash.new }
- get '/dont_set_flash', nil, env
- assert_raise(ActionDispatch::ClosedError) {
- @request.flash['alert'] = 'alert'
- }
- end
- end
-
- def test_setting_flash_now_raises_after_stream_back_to_client
- with_test_route_set do
- env = { 'action_dispatch.request.flash_hash' => ActionDispatch::Flash::FlashHash.new }
- get '/set_flash_now', nil, env
- assert_raise(ActionDispatch::ClosedError) {
- @request.flash.now['alert'] = 'alert'
- }
- end
- end
-
- def test_setting_flash_now_raises_after_stream_back_to_client_even_with_an_empty_flash
- with_test_route_set do
- env = { 'action_dispatch.request.flash_hash' => ActionDispatch::Flash::FlashHash.new }
- get '/dont_set_flash', nil, env
- assert_raise(ActionDispatch::ClosedError) {
- @request.flash.now['alert'] = 'alert'
- }
- end
- end
-
private
# Overwrite get to send SessionSecret in env hash
diff --git a/actionpack/test/controller/new_base/render_template_test.rb b/actionpack/test/controller/new_base/render_template_test.rb
index ba804421da..ade204c387 100644
--- a/actionpack/test/controller/new_base/render_template_test.rb
+++ b/actionpack/test/controller/new_base/render_template_test.rb
@@ -59,6 +59,12 @@ module RenderTemplate
def with_error
render :template => "test/with_error"
end
+
+ private
+
+ def show_detailed_exceptions?
+ request.local?
+ end
end
class TestWithoutLayout < Rack::TestCase
diff --git a/actionpack/test/controller/show_exceptions_test.rb b/actionpack/test/controller/show_exceptions_test.rb
index 5eff1eb09d..13ab19ed8f 100644
--- a/actionpack/test/controller/show_exceptions_test.rb
+++ b/actionpack/test/controller/show_exceptions_test.rb
@@ -2,12 +2,24 @@ require 'abstract_unit'
module ShowExceptions
class ShowExceptionsController < ActionController::Base
- use ActionDispatch::ShowExceptions
+ use ActionDispatch::ShowExceptions, ActionDispatch::PublicExceptions.new("#{FIXTURE_LOAD_PATH}/public")
use ActionDispatch::DebugExceptions
+ before_filter :only => :another_boom do
+ request.env["action_dispatch.show_detailed_exceptions"] = true
+ end
+
def boom
raise 'boom!'
end
+
+ def another_boom
+ raise 'boom!'
+ end
+
+ def show_detailed_exceptions?
+ request.local?
+ end
end
class ShowExceptionsTest < ActionDispatch::IntegrationTest
@@ -18,7 +30,7 @@ module ShowExceptions
assert_equal "500 error fixture\n", body
end
- test 'show diagnostics from a local ip' do
+ test 'show diagnostics from a local ip if show_detailed_exceptions? is set to request.local?' do
@app = ShowExceptionsController.action(:boom)
['127.0.0.1', '127.0.0.127', '::1', '0:0:0:0:0:0:0:1', '0:0:0:0:0:0:0:1%0'].each do |ip_address|
self.remote_addr = ip_address
@@ -27,9 +39,8 @@ module ShowExceptions
end
end
- test 'show diagnostics from a remote ip when consider_all_requests_local is true' do
- ShowExceptionsController.any_instance.stubs(:consider_all_requests_local).returns(true)
- @app = ShowExceptionsController.action(:boom)
+ test 'show diagnostics from a remote ip when env is already set' do
+ @app = ShowExceptionsController.action(:another_boom)
self.remote_addr = '208.77.188.166'
get '/'
assert_match(/boom/, body)
diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb
index dc07e07cb9..288efbf7c3 100644
--- a/actionpack/test/controller/url_for_test.rb
+++ b/actionpack/test/controller/url_for_test.rb
@@ -71,6 +71,14 @@ module AbstractController
)
end
+ def test_subdomain_may_be_object
+ model = mock(:to_param => 'api')
+ add_host!
+ assert_equal('http://api.basecamphq.com/c/a/i',
+ W.new.url_for(:subdomain => model, :controller => 'c', :action => 'a', :id => 'i')
+ )
+ end
+
def test_subdomain_may_be_removed
add_host!
assert_equal('http://basecamphq.com/c/a/i',
diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb
index 3765b7eb44..6ebd02e85c 100644
--- a/actionpack/test/dispatch/cookies_test.rb
+++ b/actionpack/test/dispatch/cookies_test.rb
@@ -564,100 +564,4 @@ class CookiesTest < ActionController::TestCase
assert_not_equal expected.split("\n"), header
end
end
-end
-
-class CookiesIntegrationTest < ActionDispatch::IntegrationTest
- SessionKey = '_myapp_session'
- SessionSecret = 'b3c631c314c0bbca50c1b2843150fe33'
-
- class TestController < ActionController::Base
- def dont_set_cookies
- head :ok
- end
-
- def set_cookies
- cookies["that"] = "hello"
- head :ok
- end
- end
-
- def test_setting_cookies_raises_after_stream_back_to_client
- with_test_route_set do
- get '/set_cookies'
- assert_raise(ActionDispatch::ClosedError) {
- request.cookie_jar['alert'] = 'alert'
- cookies['alert'] = 'alert'
- }
- end
- end
-
- def test_setting_cookies_raises_after_stream_back_to_client_even_without_cookies
- with_test_route_set do
- get '/dont_set_cookies'
- assert_raise(ActionDispatch::ClosedError) {
- request.cookie_jar['alert'] = 'alert'
- }
- end
- end
-
- def test_setting_permanent_cookies_raises_after_stream_back_to_client
- with_test_route_set do
- get '/set_cookies'
- assert_raise(ActionDispatch::ClosedError) {
- request.cookie_jar.permanent['alert'] = 'alert'
- cookies['alert'] = 'alert'
- }
- end
- end
-
- def test_setting_permanent_cookies_raises_after_stream_back_to_client_even_without_cookies
- with_test_route_set do
- get '/dont_set_cookies'
- assert_raise(ActionDispatch::ClosedError) {
- request.cookie_jar.permanent['alert'] = 'alert'
- }
- end
- end
-
- def test_setting_signed_cookies_raises_after_stream_back_to_client
- with_test_route_set do
- get '/set_cookies'
- assert_raise(ActionDispatch::ClosedError) {
- request.cookie_jar.signed['alert'] = 'alert'
- cookies['alert'] = 'alert'
- }
- end
- end
-
- def test_setting_signed_cookies_raises_after_stream_back_to_client_even_without_cookies
- with_test_route_set do
- get '/dont_set_cookies'
- assert_raise(ActionDispatch::ClosedError) {
- request.cookie_jar.signed['alert'] = 'alert'
- }
- end
- end
-
- private
-
- # Overwrite get to send SessionSecret in env hash
- def get(path, parameters = nil, env = {})
- env["action_dispatch.secret_token"] ||= SessionSecret
- super
- end
-
- def with_test_route_set
- with_routing do |set|
- set.draw do
- match ':action', :to => CookiesIntegrationTest::TestController
- end
-
- @app = self.class.build_app(set) do |middleware|
- middleware.use ActionDispatch::Cookies
- middleware.delete "ActionDispatch::ShowExceptions"
- end
-
- yield
- end
- end
-end
+end \ No newline at end of file
diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb
index 6133bfe338..f3dc160d7d 100644
--- a/actionpack/test/dispatch/debug_exceptions_test.rb
+++ b/actionpack/test/dispatch/debug_exceptions_test.rb
@@ -3,8 +3,18 @@ require 'abstract_unit'
class DebugExceptionsTest < ActionDispatch::IntegrationTest
class Boomer
+ attr_accessor :closed
+
def initialize(detailed = false)
@detailed = detailed
+ @closed = false
+ end
+
+ def each
+ end
+
+ def close
+ @closed = true
end
def call(env)
@@ -12,7 +22,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
req = ActionDispatch::Request.new(env)
case req.path
when "/pass"
- [404, { "X-Cascade" => "pass" }, []]
+ [404, { "X-Cascade" => "pass" }, self]
when "/not_found"
raise ActionController::UnknownAction
when "/runtime_error"
@@ -31,8 +41,8 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
end
end
- ProductionApp = ActionDispatch::DebugExceptions.new((Boomer.new(false)))
- DevelopmentApp = ActionDispatch::DebugExceptions.new((Boomer.new(true)))
+ ProductionApp = ActionDispatch::DebugExceptions.new(Boomer.new(false))
+ DevelopmentApp = ActionDispatch::DebugExceptions.new(Boomer.new(true))
test 'skip diagnosis if not showing detailed exceptions' do
@app = ProductionApp
@@ -55,6 +65,15 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
end
end
+ test 'closes the response body on cascade pass' do
+ boomer = Boomer.new(false)
+ @app = ActionDispatch::DebugExceptions.new(boomer)
+ assert_raise ActionController::RoutingError do
+ get "/pass", {}, {'action_dispatch.show_exceptions' => true}
+ end
+ assert boomer.closed, "Expected to close the response body"
+ end
+
test "rescue with diagnostics message" do
@app = DevelopmentApp
@@ -133,6 +152,6 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
'action_dispatch.backtrace_cleaner' => backtrace_cleaner}
get "/", {}, env
- assert_operator (output.rewind && output.read).lines.count, :>, 10
+ assert_operator((output.rewind && output.read).lines.count, :>, 10)
end
end
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index bc4e2e31c8..5325f81364 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -91,6 +91,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
match "/local/:action", :controller => "local"
match "/projects/status(.:format)"
+ match "/404", :to => lambda { |env| [404, {"Content-Type" => "text/plain"}, ["NOT FOUND"]] }
constraints(:ip => /192\.168\.1\.\d\d\d/) do
get 'admin' => "queenbee#index"
diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb
index 020cc80f3f..e9504f3524 100644
--- a/actionpack/test/dispatch/show_exceptions_test.rb
+++ b/actionpack/test/dispatch/show_exceptions_test.rb
@@ -18,9 +18,9 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest
end
end
- ProductionApp = ActionDispatch::ShowExceptions.new(Boomer.new)
+ ProductionApp = ActionDispatch::ShowExceptions.new(Boomer.new, ActionDispatch::PublicExceptions.new("#{FIXTURE_LOAD_PATH}/public"))
- test 'skip diagnosis if not showing exceptions' do
+ test "skip exceptions app if not showing exceptions" do
@app = ProductionApp
assert_raise RuntimeError do
get "/", {}, {'action_dispatch.show_exceptions' => false}
@@ -75,4 +75,28 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest
assert_response 404
assert_match(/404 error/, body)
end
+
+ test "calls custom exceptions app" do
+ exceptions_app = lambda do |env|
+ assert_kind_of AbstractController::ActionNotFound, env["action_dispatch.exception"]
+ assert_equal "/404", env["PATH_INFO"]
+ [404, { "Content-Type" => "text/plain" }, ["YOU FAILED BRO"]]
+ end
+
+ @app = ActionDispatch::ShowExceptions.new(Boomer.new, exceptions_app)
+ get "/not_found_original_exception", {}, {'action_dispatch.show_exceptions' => true}
+ assert_response 404
+ assert_equal "YOU FAILED BRO", body
+ end
+
+ test "returns an empty response if custom exceptions app returns X-Cascade pass" do
+ exceptions_app = lambda do |env|
+ [404, { "X-Cascade" => "pass" }, []]
+ end
+
+ @app = ActionDispatch::ShowExceptions.new(Boomer.new, exceptions_app)
+ get "/method_not_allowed", {}, {'action_dispatch.show_exceptions' => true}
+ assert_response 405
+ assert_equal "", body
+ end
end
diff --git a/actionpack/test/template/compiled_templates_test.rb b/actionpack/test/template/compiled_templates_test.rb
index 8fc78283d8..30d798d693 100644
--- a/actionpack/test/template/compiled_templates_test.rb
+++ b/actionpack/test/template/compiled_templates_test.rb
@@ -3,6 +3,10 @@ require 'controller/fake_models'
class CompiledTemplatesTest < Test::Unit::TestCase
def setup
+ # Clean up any details key cached to expose failures
+ # that otherwise would appear just on isolated tests
+ ActionView::LookupContext::DetailsKey.clear
+
@compiled_templates = ActionView::CompiledTemplates
@compiled_templates.instance_methods.each do |m|
@compiled_templates.send(:remove_method, m) if m =~ /^_render_template_/
diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb
index 57a5895cec..fadfb59572 100644
--- a/actionpack/test/template/date_helper_test.rb
+++ b/actionpack/test/template/date_helper_test.rb
@@ -1396,6 +1396,25 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, date_select("post", "written_on", :order => [ :month, :year ])
end
+ def test_date_select_without_day_with_separator
+ @post = Post.new
+ @post.written_on = Date.new(2004, 6, 15)
+
+ expected = "<input type=\"hidden\" id=\"post_written_on_3i\" name=\"post[written_on(3i)]\" value=\"1\" />\n"
+
+ expected << %{<select id="post_written_on_2i" name="post[written_on(2i)]">\n}
+ expected << %{<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6" selected="selected">June</option>\n<option value="7">July</option>\n<option value="8">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n}
+ expected << "</select>\n"
+
+ expected << "/"
+
+ expected << %{<select id="post_written_on_1i" name="post[written_on(1i)]">\n}
+ expected << %{<option value="1999">1999</option>\n<option value="2000">2000</option>\n<option value="2001">2001</option>\n<option value="2002">2002</option>\n<option value="2003">2003</option>\n<option value="2004" selected="selected">2004</option>\n<option value="2005">2005</option>\n<option value="2006">2006</option>\n<option value="2007">2007</option>\n<option value="2008">2008</option>\n<option value="2009">2009</option>\n}
+ expected << "</select>\n"
+
+ assert_dom_equal expected, date_select("post", "written_on", :date_separator => '/', :order => [ :month, :year ])
+ end
+
def test_date_select_without_day_and_with_disabled_html_option
@post = Post.new
@post.written_on = Date.new(2004, 6, 15)
diff --git a/actionpack/test/template/lookup_context_test.rb b/actionpack/test/template/lookup_context_test.rb
index bac2530e3d..c65f707da0 100644
--- a/actionpack/test/template/lookup_context_test.rb
+++ b/actionpack/test/template/lookup_context_test.rb
@@ -1,20 +1,14 @@
require "abstract_unit"
require "abstract_controller/rendering"
-ActionView::LookupContext::DetailsKey.class_eval do
- def self.details_keys
- @details_keys
- end
-end
-
class LookupContextTest < ActiveSupport::TestCase
def setup
@lookup_context = ActionView::LookupContext.new(FIXTURE_LOAD_PATH, {})
+ ActionView::LookupContext::DetailsKey.clear
end
def teardown
I18n.locale = :en
- ActionView::LookupContext::DetailsKey.details_keys.clear
end
test "process view paths on initialization" do