QutBioacoustics/baw-server

View on GitHub
app/controllers/errors_controller.rb

Summary

Maintainability
A
1 hr
Test Coverage
# frozen_string_literal: true

class ErrorsController < ApplicationController
  skip_authorization_check only: [:route_error, :uncaught_error, :test_exceptions, :show, :method_not_allowed_error]

  # see application_controller.rb for error handling for specific exceptions.
  # see routes.rb for the catch-all route for routing errors.
  # see application.rb for the exceptions_app settings.

  def show
    error_code_or_id = params[:name]

    status_symbol = :bad_request
    detail_message = 'There was a problem with your request. Perhaps go back and try again?'
    error = nil
    method_name = 'errors_show'
    additional_info = { error_info: { original_http_method: request.method } }

    case error_code_or_id
    when 400, '400', 'bad_request'
      status_symbol = :bad_request
    when 401, '401', 'unauthorized', 'unauthorised'
      status_symbol = :unauthorized
      detail_message = I18n.t('devise.failure.unauthenticated')
      additional_info[:error_links] = [:sign_in, :sign_up, :confirm]
    when 403, '403', 'forbidden'
      status_symbol = :forbidden
      detail_message = I18n.t('devise.failure.unauthorized')
      additional_info[:error_links] = [:permissions, :confirm]
    when 404, '404', 'not_found'
      status_symbol = :not_found
      detail_message = 'Could not find the requested page.'
    when 405, '405', 'method_not_allowed'
      status_symbol = :method_not_allowed
      detail_message = 'HTTP method not allowed for this resource.'
    when 406, '406', 'not_acceptable'
      status_symbol = :not_acceptable
      detail_message = 'We cold not provide the format you asked for. Perhaps try a different file extension?'
      additional_info[:error_info][:available_formats] = Settings.supported_media_types
    when 409, '409', 'conflict'
      status_symbol = :conflict
      detail_message = 'There was a conflict in the request. This could be due to duplicate ' \
                       'items that need to be unique or multiple edits at the same time.'
    when 410, '410', 'gone'
      status_symbol = :gone
      detail_message = 'This content is no longer available.'
    when 415, '415', 'unsupported_media_type'
      status_symbol = :unsupported_media_type
      detail_message = 'The format of your request is not supported. Perhaps try a different format?'
      additional_info[:error_info][:available_formats] = Settings.supported_media_types
    when 416, '416', 'range_not_satisfiable'
      status_symbol = :range_not_satisfiable
      detail_message = 'That range is not available. Check that the range is within the file.'
    when 429, '429', 'too_many_requests'
      status_symbol = :too_many_requests
      detail_message = "There have been too many requests. Take it easy, we're doing our best here."
    end

    render_error(status_symbol, detail_message, error, method_name, additional_info)
  end

  def route_error
    render_error(
      :not_found,
      'Could not find the requested page.',
      nil,
      'route_error',
      { error_info: { original_route: params[:requested_route], original_http_method: request.method } }
    )
  end

  def method_not_allowed_error
    render_error(
      :method_not_allowed,
      'HTTP method not allowed for this resource.',
      nil,
      'method_not_allowed_error',
      { error_info: { original_route: params[:requested_route], original_http_method: request.method } }
    )
  end

  def uncaught_error
    # called with env as a parameter

    # http://geekmonkey.org/articles/29-exception-applications-in-rails-3-2
    # for friendly responses to exceptions
    # only used when:
    # Rails.application.config.consider_all_requests_local = false
    # Rails.application.config.action_dispatch.show_exceptions = true
    # https://github.com/s-andringa/recipes_exceptions_example/blob/b28b42f2b96c808bde93badbb05aff0bdc2c7fe9/app/controllers/exception_controller.rb

    error = request.env['action_dispatch.exception']
    exception_wrapper = ActionDispatch::ExceptionWrapper.new(request.env, error)
    status_code = exception_wrapper.status_code
    rescue_response = exception_wrapper.rescue_responses[error.class.name]
    #rescue_template = exception_wrapper.rescue_template[error.class.name]
    detail_message = Rack::Utils::HTTP_STATUS_CODES[status_code].humanize
    #error_name = error.class.name.titleize
    #error_message = error.message.underscore.humanize

    # give basic information about the error
    # do not reveal information about the error
    render_error(
      rescue_response,
      detail_message,
      error,
      'uncaught_error'
    )

    # I18n.with_options scope: [:exception, :show, rescue_response], exception_name: error.class.name, exception_message: error.message do |i18n|
    #   code = status_code
    #
    #   name = i18n.t "#{error.class.name.underscore}.title", default: i18n.t(:title, default: error.class.name)
    #   message = i18n.t "#{error.class.name.underscore}.description", default: i18n.t(:description, default: error.message)
    # end
  end

  def test_exceptions
    if BawApp.test? && params.include?(:exception_class)
      msg = 'Purposeful exception raised for testing.'
      error_class_string = params[:exception_class]

      # Unsafe reflection method constantize called with parameter value.
      # I think this is ok as it's only available in test env.
      error_class = error_class_string.constantize

      case error_class_string
      when 'ActionController::BadRequest'
        raise error_class, response

      when 'ActiveRecord::RecordNotUnique'
        raise error_class, msg

      when 'CustomErrors::UnsupportedMediaTypeError',
            'CustomErrors::NotAcceptableError'
        raise error_class.new(msg, Settings.supported_media_types)

      else
        raise error_class, msg
      end

    end
  end
end