aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb24
-rw-r--r--actionpack/test/dispatch/debug_exceptions_test.rb31
-rw-r--r--activesupport/lib/active_support/actionable_error.rb23
-rw-r--r--activesupport/test/actionable_error_test.rb15
4 files changed, 67 insertions, 26 deletions
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb
index e181b6c539..b6c6d2f50d 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb
@@ -1,15 +1,13 @@
-<% if ActiveSupport::ActionableError === exception %>
- <% actions = ActiveSupport::ActionableError.actions(exception) %>
+<% actions = ActiveSupport::ActionableError.actions(exception) %>
- <% if actions.any? %>
- <div class="actions">
- <% actions.each do |action, _| %>
- <%= button_to action, ActionDispatch::ActionableExceptions.endpoint, params: {
- error: exception.class.name,
- action: action,
- location: request.path
- } %>
- <% end %>
- </div>
- <% end %>
+<% if actions.any? %>
+ <div class="actions">
+ <% actions.each do |action, _| %>
+ <%= button_to action, ActionDispatch::ActionableExceptions.endpoint, params: {
+ error: exception.class.name,
+ action: action,
+ location: request.path
+ } %>
+ <% end %>
+ </div>
<% end %>
diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb
index 2812b1b614..5ae8a20ae4 100644
--- a/actionpack/test/dispatch/debug_exceptions_test.rb
+++ b/actionpack/test/dispatch/debug_exceptions_test.rb
@@ -5,6 +5,18 @@ require "abstract_unit"
class DebugExceptionsTest < ActionDispatch::IntegrationTest
InterceptedErrorInstance = StandardError.new
+ class CustomActionableError < StandardError
+ include ActiveSupport::ActionableError
+
+ action "Action 1" do
+ nil
+ end
+
+ action "Action 2" do
+ nil
+ end
+ end
+
class Boomer
attr_accessor :closed
@@ -92,6 +104,8 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
method_that_raises
when "/nested_exceptions"
raise_nested_exceptions
+ when %r{/actionable_error}
+ raise CustomActionableError
else
raise "puke!"
end
@@ -589,4 +603,21 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
end
end
end
+
+ test "shows a buttons for every action in an actionable error" do
+ @app = DevelopmentApp
+ Rails.stub :root, Pathname.new(".") do
+ cleaner = ActiveSupport::BacktraceCleaner.new.tap do |bc|
+ bc.add_silencer { |line| line !~ %r{test/dispatch/debug_exceptions_test.rb} }
+ end
+
+ get "/actionable_error", headers: { "action_dispatch.backtrace_cleaner" => cleaner }
+
+ # Assert correct error
+ assert_response 500
+
+ assert_select 'input[value="Action 1"]'
+ assert_select 'input[value="Action 2"]'
+ end
+ end
end
diff --git a/activesupport/lib/active_support/actionable_error.rb b/activesupport/lib/active_support/actionable_error.rb
index aeee2177aa..be4972759b 100644
--- a/activesupport/lib/active_support/actionable_error.rb
+++ b/activesupport/lib/active_support/actionable_error.rb
@@ -15,20 +15,25 @@ module ActiveSupport
NonActionable = Class.new(StandardError)
- included do
- class_attribute :_actions, default: Hash.new do |_, label|
- raise NonActionable, "Cannot find action \"#{label}\" for #{self}"
- end
+ NoActions = Hash.new do |_, label| # :nodoc:
+ raise NonActionable, "Cannot find action \"#{label}\" for #{self}"
end
- def self.===(other) # :nodoc:
- super || Module === other && other.ancestors.include?(self)
+ included do
+ class_attribute :_actions, default: NoActions.dup
end
def self.actions(error) # :nodoc:
- error = error.constantize if String === error
- raise NonActionable, "#{error.name} is non-actionable" unless self === error
- error._actions
+ case error
+ when String
+ actions(error.constantize)
+ when ActionableError, -> it { Class === it && it < ActionableError }
+ error._actions
+ when Exception
+ NoActions
+ else
+ raise NonActionable, "#{error} is non-actionable"
+ end
end
def self.dispatch(error, label) # :nodoc:
diff --git a/activesupport/test/actionable_error_test.rb b/activesupport/test/actionable_error_test.rb
index 66ba94e0dd..80614b4700 100644
--- a/activesupport/test/actionable_error_test.rb
+++ b/activesupport/test/actionable_error_test.rb
@@ -4,8 +4,7 @@ require "abstract_unit"
require "active_support/actionable_error"
class ActionableErrorTest < ActiveSupport::TestCase
- class NonActionableError < StandardError
- end
+ NonActionableError = Class.new(StandardError)
class DispatchableError < StandardError
include ActiveSupport::ActionableError
@@ -22,15 +21,23 @@ class ActionableErrorTest < ActiveSupport::TestCase
end
end
- test "can get all action of an actionable error" do
+ test "lists all action of an actionable error" do
assert_equal ["Flip 1", "Flip 2"], ActiveSupport::ActionableError.actions(DispatchableError).keys
assert_equal ["Flip 1", "Flip 2"], ActiveSupport::ActionableError.actions(DispatchableError.new).keys
end
- test "cannot get actions from non-actionable errors" do
+ test "raises an error when trying to get actions from non-actionable error classes" do
assert_raises ActiveSupport::ActionableError::NonActionable do
ActiveSupport::ActionableError.actions(NonActionableError)
end
+
+ assert_raises ActiveSupport::ActionableError::NonActionable do
+ ActiveSupport::ActionableError.actions(NonActionableError.name)
+ end
+ end
+
+ test "returns no actions from non-actionable exception instances" do
+ assert ActiveSupport::ActionableError.actions(Exception.new).empty?
end
test "dispatches actions from class and a label" do