mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
45f1c7a3e1
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.
53 lines
1.5 KiB
Ruby
53 lines
1.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "active_support/concern"
|
|
|
|
module ActiveSupport
|
|
# Actionable errors let's you define actions to resolve an error.
|
|
#
|
|
# To make an error actionable, include the <tt>ActiveSupport::ActionableError</tt>
|
|
# module and invoke the +action+ class macro to define the action.
|
|
#
|
|
# An action needs a name and a procedure to execute. The name can be shown by
|
|
# the action dispatching mechanism.
|
|
module ActionableError
|
|
extend Concern
|
|
|
|
NonActionable = Class.new(StandardError)
|
|
|
|
included do
|
|
class_attribute :_actions, default: Hash.new do |_, label|
|
|
raise NonActionable, "Cannot find action \"#{label}\" for #{self}"
|
|
end
|
|
end
|
|
|
|
def self.===(other) # :nodoc:
|
|
super || Module === other && other.ancestors.include?(self)
|
|
end
|
|
|
|
def self.actions(error) # :nodoc:
|
|
error = error.constantize if String === error
|
|
raise NonActionable, "#{error.name} is non-actionable" unless self === error
|
|
error._actions
|
|
end
|
|
|
|
def self.dispatch(error, label) # :nodoc:
|
|
actions(error)[label].call
|
|
end
|
|
|
|
module ClassMethods
|
|
# Defines an action that can resolve the error.
|
|
#
|
|
# class PendingMigrationError < MigrationError
|
|
# include ActiveSupport::ActionableError
|
|
#
|
|
# action "Run pending migrations" do
|
|
# ActiveRecord::Tasks::DatabaseTasks.migrate
|
|
# end
|
|
# end
|
|
def action(label, &block)
|
|
_actions[label] = block
|
|
end
|
|
end
|
|
end
|
|
end
|