diff options
author | Genadi Samokovarov <gsamokovarov@gmail.com> | 2018-12-25 16:35:15 +0200 |
---|---|---|
committer | Genadi Samokovarov <gsamokovarov@gmail.com> | 2019-04-19 14:14:06 +0900 |
commit | 45f1c7a3e16437e517baa6606674f7bbb16dba74 (patch) | |
tree | 62fb0c46cd72368c2b8806c43612e809b45996a5 /activesupport/lib | |
parent | 16dae7684edc480ee3fe65dfff8e19989402c987 (diff) | |
download | rails-45f1c7a3e16437e517baa6606674f7bbb16dba74.tar.gz rails-45f1c7a3e16437e517baa6606674f7bbb16dba74.tar.bz2 rails-45f1c7a3e16437e517baa6606674f7bbb16dba74.zip |
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.
Diffstat (limited to 'activesupport/lib')
-rw-r--r-- | activesupport/lib/active_support.rb | 1 | ||||
-rw-r--r-- | activesupport/lib/active_support/actionable_error.rb | 53 |
2 files changed, 54 insertions, 0 deletions
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 5589c71281..40a9181493 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -33,6 +33,7 @@ require "active_support/core_ext/date_and_time/compatibility" module ActiveSupport extend ActiveSupport::Autoload + autoload :ActionableError autoload :Concern autoload :CurrentAttributes autoload :Dependencies diff --git a/activesupport/lib/active_support/actionable_error.rb b/activesupport/lib/active_support/actionable_error.rb new file mode 100644 index 0000000000..aeee2177aa --- /dev/null +++ b/activesupport/lib/active_support/actionable_error.rb @@ -0,0 +1,53 @@ +# 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 |