Low commit activity in last 3 years
A long-lived project that still receives updates
Common exception `rescue_from` handling for OpenStax sites.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies
 Project Readme

RescueFrom

Gem Version Tests Code Climate

This is the gem that brings together disparate systems within OpenStax and abstracts consistent exception rescuing with html and json responses, and email notifying

Installation

Add this line to your application's Gemfile:

gem 'rescue_from'

And then execute:

$ bundle

Or install it yourself as:

$ gem install rescue_from

Usage

Run the install generator to get the config initializer

$ rails g openstax:rescue_from:install

You can override the controller action that renders the error templates:

class ApplicationController < ActionController::Base
  # Override the rescued hook which is called when configuration.raise_exceptions is false
  # (See 'Controller hook')
  #
  # def openstax_exception_rescued(exception_proxy, did_notify)
  #   app_name = openstax_rescue_config.app_name
  #     # RescueFrom.configuration private method available to you
  #
  #   respond_to do |f|
  #     f.xml { render plain: "I respond strangely to the XML format!",
  #                    status: exception_proxy.status }
  #   end
  # end
end

Registering Exceptions

# Use OpenStax::RescueFrom.register_exception(exception_constant_or_string, options = {})
# to register new exceptions or override the options of existing ones

OpenStax::RescueFrom.register_exception(SecurityTransgression, status: 403,
                                                               extras: -> (exception) {
                                                                 { headers: exception.response.headers }
                                                               })

OpenStax::RescueFrom.register_exception('ActiveRecord::RecordNotFound', notify: false,
                                                                        status: 404)

Note: If you want to define extras, you must use a function that accepts exception as its argument

Configuration

This configuration, which is placed in ./config/initializers/rescue_from.rb by the install generator, shows the defaults:

OpenStax::RescueFrom.configure do |config|
  config.raise_exceptions = ![false, 'false'].include?(ENV['RAISE_EXCEPTIONS']) ||
                              Rails.application.config.consider_all_requests_local

  config.app_name = ENV['APP_NAME']
  # Can be a name, or a web/email address. See 'View helper' below
  config.contact_name = ENV['EXCEPTION_CONTACT_NAME']

  # To use ExceptionNotifier add `gem 'exception_notification'` to your Gemfile and then:
  # config.notify_proc = ->(proxy, controller) do
  #   ExceptionNotifier.notify_exception(
  #     proxy.exception,
  #     env: controller.request.env,
  #     data: {
  #       error_id: proxy.error_id,
  #       class: proxy.name,
  #       message: proxy.message,
  #       first_line_of_backtrace: proxy.first_backtrace_line,
  #       cause: proxy.cause,
  #       dns_name: resolve_ip(controller.request.remote_ip),
  #       extras: proxy.extras
  #     },
  #     sections: %w(data request session environment backtrace)
  #   )
  # end
  # config.notify_background_proc = ->(proxy) do
  #   ExceptionNotifier.notify_exception(
  #     proxy.exception,
  #     data: {
  #       error_id: proxy.error_id,
  #       class: proxy.name,
  #       message: proxy.message,
  #       first_line_of_backtrace: proxy.first_backtrace_line,
  #       cause: proxy.cause,
  #       extras: proxy.extras
  #     },
  #     sections: %w(data environment backtrace)
  #   )
  # end
  # config.notify_rack_middleware = ExceptionNotification::Rack
  # config.notify_rack_middleware_options = {
  #   email: {
  #     email_prefix: "[#{config.app_name}] (#{ENV['APP_ENV']}) ",
  #     sender_address: ENV['EXCEPTION_SENDER'],
  #     exception_recipients: ENV['EXCEPTION_RECIPIENTS']
  #   }
  # }
  # URL generation errors are caused by bad routes, for example, and should not be ignored
  # ExceptionNotifier.ignored_exceptions.delete("ActionController::UrlGenerationError")

  # To use Raven (Sentry) add `gem 'sentry-raven', require: 'raven/base'` to your Gemfile and then:
  # config.notify_proc = -> do |proxy, controller|
  #   extra = {
  #     error_id: proxy.error_id,
  #     class: proxy.name,
  #     message: proxy.message,
  #     first_line_of_backtrace: proxy.first_backtrace_line,
  #     cause: proxy.cause,
  #     dns_name: resolve_ip(controller.request.remote_ip)
  #   }
  #   extra.merge!(proxy.extras) if proxy.extras.is_a? Hash
  #
  #   Raven.capture_exception(proxy.exception, extra: extra)
  # end
  # config.notify_background_proc = -> do |proxy|
  #   extra = {
  #     error_id: proxy.error_id,
  #     class: proxy.name,
  #     message: proxy.message,
  #     first_line_of_backtrace: proxy.first_backtrace_line,
  #     cause: proxy.cause
  #   }
  #   extra.merge!(proxy.extras) if proxy.extras.is_a? Hash
  #
  #   Raven.capture_exception(proxy.exception, extra: extra)
  # end
  # require 'raven/integrations/rack'
  # config.notify_rack_middleware = Raven::Rack

  config.html_error_template_path = 'errors/any'
  config.html_error_template_layout_name = 'application'
end

# Exceptions in controllers might be reraised or not depending on the settings above
ActionController::Base.use_openstax_exception_rescue

# RescueFrom always reraises background exceptions so that the background job may properly fail
ActiveJob::Base.use_openstax_exception_rescue

Controller hook

#
#             -- Mixed in Controller module instance method --
#
#       -- this method is ONLY called when Exceptions are not raised --
#
# -- check your OpenStax::RescueFrom.configuration.raise_exceptions setting --
#
# Params:
#   exception_proxy - an OpenStax::RescueFrom::ExceptionProxy wrapper around
#     the exception
#   did_notify - true if the exception was sent out to notification channels
#     such as email or the log file
#

def openstax_exception_rescued(exception_proxy, did_notify)
  @message = exception_proxy.friendly_message
  @status = exception_proxy.status
  @error_id = exception_proxy.error_id
  @did_notify = did_notify

  respond_to do |f|
    f.html { render template: openstax_rescue_config.html_error_template_path,
                    layout: openstax_rescue_config.html_error_template_layout_name,
                    status: exception_proxy.status }
    f.json { render json: { error_id: exception_proxy.error_id }
                    status: exception_proxy.status }
    f.all { head exception_proxy.status }
  end
end

# Just override this method in your own controller if you wish

You will readily note that for HTML response, there is an error template rendered from within the gem. See below for overriding these default views.

Override the views

You can either declare your own template path variables:

OpenStax::RescueFrom.configure do |config|
  config.html_error_template_path = 'my/path'
  config.html_error_template_layout_name = 'my_layout'
end

or, you can generate the views into the default path:

$ rails g open_stax:rescue_from:views

View helper

The gem provides an openstax_rescue_from_contact_info view helper that uses OpenStax::RescueFrom.configuration.contact_name to provide either just the name, or to link web and email addresses automatically for you.

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/openstax/rescue_from.

License

The gem is available as open source under the terms of the MIT License.