From 45f1c7a3e16437e517baa6606674f7bbb16dba74 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Tue, 25 Dec 2018 16:35:15 +0200 Subject: Introduce Actionable Errors Actionable errors let's you dispatch actions from Rails' error pages. This can help you save time if you have a clear action for the resolution of common development errors. The de-facto example are pending migrations. Every time pending migrations are found, a middleware raises an error. With actionable errors, you can run the migrations right from the error page. Other examples include Rails plugins that need to run a rake task to setup themselves. They can now raise actionable errors to run the setup straight from the error pages. Here is how to define an actionable error: ```ruby class PendingMigrationError < MigrationError #:nodoc: include ActiveSupport::ActionableError action "Run pending migrations" do ActiveRecord::Tasks::DatabaseTasks.migrate end end ``` To make an error actionable, include the `ActiveSupport::ActionableError` module and invoke the `action` class macro to define the action. An action needs a name and a procedure to execute. The name is shown as the name of a button on the error pages. Once clicked, it will invoke the given procedure. --- .../middleware/actionable_exceptions.rb | 39 ++++++++++++++++++++++ .../action_dispatch/middleware/debug_exceptions.rb | 4 ++- .../lib/action_dispatch/middleware/debug_view.rb | 4 +++ .../middleware/templates/rescues/_actions.html.erb | 15 +++++++++ .../middleware/templates/rescues/_actions.text.erb | 0 .../templates/rescues/diagnostics.html.erb | 6 +++- .../middleware/templates/rescues/layout.erb | 4 +++ 7 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 actionpack/lib/action_dispatch/middleware/actionable_exceptions.rb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb create mode 100644 actionpack/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb (limited to 'actionpack/lib/action_dispatch/middleware') diff --git a/actionpack/lib/action_dispatch/middleware/actionable_exceptions.rb b/actionpack/lib/action_dispatch/middleware/actionable_exceptions.rb new file mode 100644 index 0000000000..f76ea7c2e2 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/actionable_exceptions.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require "erb" +require "action_dispatch/http/request" +require "active_support/actionable_error" + +module ActionDispatch + class ActionableExceptions # :nodoc: + cattr_accessor :endpoint, default: "/rails/actions" + + def initialize(app) + @app = app + end + + def call(env) + request = ActionDispatch::Request.new(env) + return @app.call(env) unless actionable_request?(request) + + ActiveSupport::ActionableError.dispatch(request.params["error"], request.params["action"]) + + redirect_to request.params["location"] + end + + private + def actionable_request?(request) + request.post? && request.path == endpoint + end + + def redirect_to(location) + body = "You are being redirected." + + [302, { + "Content-Type" => "text/html; charset=#{Response.default_charset}", + "Content-Length" => body.bytesize.to_s, + "Location" => location, + }, [body]] + end + end +end diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb index 59113e13f4..a679f9bf01 100644 --- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb @@ -4,6 +4,8 @@ require "action_dispatch/http/request" require "action_dispatch/middleware/exception_wrapper" require "action_dispatch/routing/inspector" +require "active_support/actionable_error" + require "action_view" require "action_view/base" @@ -19,7 +21,7 @@ module ActionDispatch end def initialize(app, routes_app = nil, response_format = :default, interceptors = self.class.interceptors) - @app = app + @app = ActionableExceptions.new(app) @routes_app = routes_app @response_format = response_format @interceptors = interceptors diff --git a/actionpack/lib/action_dispatch/middleware/debug_view.rb b/actionpack/lib/action_dispatch/middleware/debug_view.rb index 43c0a84504..a03650254e 100644 --- a/actionpack/lib/action_dispatch/middleware/debug_view.rb +++ b/actionpack/lib/action_dispatch/middleware/debug_view.rb @@ -52,5 +52,9 @@ module ActionDispatch super end end + + def protect_against_forgery? + false + end end end diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb new file mode 100644 index 0000000000..e181b6c539 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb @@ -0,0 +1,15 @@ +<% if ActiveSupport::ActionableError === exception %> + <% actions = ActiveSupport::ActionableError.actions(exception) %> + + <% if actions.any? %> +
+ <% actions.each do |action, _| %> + <%= button_to action, ActionDispatch::ActionableExceptions.endpoint, params: { + error: exception.class.name, + action: action, + location: request.path + } %> + <% end %> +
+ <% end %> +<% end %> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb index bde26f46c2..999e84e4d6 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb @@ -8,7 +8,11 @@
-

<%= h @exception.message %>

+

+ <%= h @exception.message %> + + <%= render "rescues/actions", exception: @exception, request: @request %> +

<%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx, error_index: 0 %> <%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show, error_index: 0 %> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb index 39ea25bdfc..0f78e23b7f 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb @@ -117,6 +117,10 @@ background-color: #FFCCCC; } + .button_to { + display: inline-block; + } + .hidden { display: none; } -- cgit v1.2.3 From 54df392bc51dcf424f07ccc10157a5969256ba73 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 28 Dec 2018 14:21:30 +0200 Subject: Manage ActionDispatch::ActionableExceptions from the default middleware stack --- actionpack/lib/action_dispatch/middleware/debug_exceptions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack/lib/action_dispatch/middleware') diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb index a679f9bf01..0b15c94122 100644 --- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb @@ -21,7 +21,7 @@ module ActionDispatch end def initialize(app, routes_app = nil, response_format = :default, interceptors = self.class.interceptors) - @app = ActionableExceptions.new(app) + @app = app @routes_app = routes_app @response_format = response_format @interceptors = interceptors -- cgit v1.2.3 From a3110fe20bc418034332bd01165df7fe6f20258e Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Sat, 29 Dec 2018 17:27:33 +0200 Subject: Drop the ambiguous `ActiveSupport::ActionableError#===` check --- .../middleware/templates/rescues/_actions.html.erb | 24 ++++++++++------------ 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'actionpack/lib/action_dispatch/middleware') 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? %> -
- <% actions.each do |action, _| %> - <%= button_to action, ActionDispatch::ActionableExceptions.endpoint, params: { - error: exception.class.name, - action: action, - location: request.path - } %> - <% end %> -
- <% end %> +<% if actions.any? %> +
+ <% actions.each do |action, _| %> + <%= button_to action, ActionDispatch::ActionableExceptions.endpoint, params: { + error: exception.class.name, + action: action, + location: request.path + } %> + <% end %> +
<% end %> -- cgit v1.2.3 From 769f73cc18c58021d49a3b93f1747568fe42ee5c Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Wed, 6 Feb 2019 08:55:23 +0200 Subject: Dispatch actions only if config.consider_all_requests_local is set --- actionpack/lib/action_dispatch/middleware/actionable_exceptions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack/lib/action_dispatch/middleware') diff --git a/actionpack/lib/action_dispatch/middleware/actionable_exceptions.rb b/actionpack/lib/action_dispatch/middleware/actionable_exceptions.rb index f76ea7c2e2..059fcdcfd4 100644 --- a/actionpack/lib/action_dispatch/middleware/actionable_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/actionable_exceptions.rb @@ -23,7 +23,7 @@ module ActionDispatch private def actionable_request?(request) - request.post? && request.path == endpoint + request.show_exceptions? && request.post? && request.path == endpoint end def redirect_to(location) -- cgit v1.2.3 From feaaa7576a0774471e36dc59730a886f623712e6 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 19 Apr 2019 13:49:56 +0900 Subject: Refactor after the most recent code review --- actionpack/lib/action_dispatch/middleware/actionable_exceptions.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'actionpack/lib/action_dispatch/middleware') diff --git a/actionpack/lib/action_dispatch/middleware/actionable_exceptions.rb b/actionpack/lib/action_dispatch/middleware/actionable_exceptions.rb index 059fcdcfd4..e94cc46603 100644 --- a/actionpack/lib/action_dispatch/middleware/actionable_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/actionable_exceptions.rb @@ -16,9 +16,9 @@ module ActionDispatch request = ActionDispatch::Request.new(env) return @app.call(env) unless actionable_request?(request) - ActiveSupport::ActionableError.dispatch(request.params["error"], request.params["action"]) + ActiveSupport::ActionableError.dispatch(request.params[:error].to_s.safe_constantize, request.params[:action]) - redirect_to request.params["location"] + redirect_to request.params[:location] end private -- cgit v1.2.3