Skip to content

Instantly share code, notes, and snippets.

@mreinsch
Last active June 3, 2023 00:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mreinsch/4460446 to your computer and use it in GitHub Desktop.
Save mreinsch/4460446 to your computer and use it in GitHub Desktop.
the way we are catching errors and rendering custom error pages for http://www.doorkeeperhq.com/
# encoding: UTF-8
#
# This file is in: lib/rescue_from_defaults.rb
#
# To use it, include the RescueFromDefaults in the ApplicationController (see below for example)
#
# To test it we are using rspec and steak. See below for examples.
#
class AccessDenied < RuntimeError
end
class ResourceGone < RuntimeError
end
module RescueFromDefaults
def self.catch_all_404_route_installed
@catch_all_404_route_installed
end
def self.catch_all_404_route_installed!
@catch_all_404_route_installed = true
end
def self.included(base)
base.rescue_from ::Exception, :with => :handle_internal_server_error
base.rescue_from ::ActionController::RoutingError, :with => :handle_not_found
base.rescue_from ::ActionController::UnknownController, :with => :handle_not_found
base.rescue_from ::AbstractController::ActionNotFound, :with => :render_not_found
base.rescue_from ::ActiveRecord::RecordNotFound, :with => :handle_not_found
base.rescue_from ::AccessDenied, :with => :handle_access_denied
base.rescue_from ::ResourceGone, :with => :handle_resource_gone
# 404 catch all route if not already installed
unless RescueFromDefaults.catch_all_404_route_installed
Rails.application.config.after_initialize do |app|
Rails.logger.debug "installing 404 catch all route"
app.routes.append { match '*path' => 'application#not_found' }
end
RescueFromDefaults.catch_all_404_route_installed!
end
end
# for "catch it all" route
def not_found
head_or_file(:not_found)
end
private
def handle_not_found(err)
logger.warn("not found: #{err}")
raise err if local_request?
head_or_file(:not_found)
end
def handle_resource_gone(err)
logger.warn("resource gone: #{err}")
raise err if local_request?
head_or_file(:gone)
end
def handle_access_denied(err)
logger.warn("access denied: #{err}")
raise err if local_request?
send_error_notifications(err)
head_or_file(:forbidden)
end
def handle_internal_server_error(err)
logger.warn("internal server error: #{err}")
raise err if local_request?
send_error_notifications(err)
head_or_file(:internal_server_error)
end
def local_request?
Rails.application.config.consider_all_requests_local || request.local?
end
def send_error_notifications(err)
notify_coalmine(err)
NewRelic::Agent.notice_error(err)
end
def head_or_file(status_code)
respond_to do |f|
f.html { render :file => "exceptions/#{status_code}", :status => status_code, :layout => "exceptions" }
f.any { head status_code }
end
end
end
# example usge in ApplicationController
require "rescue_from_defaults"
class ApplicationController < ActionController::Base
include RescueFromDefaults
end
# encoding: UTF-8
# for acceptance tests using rspec and steak
module ErrorPagesHelperMethods
module RspecHelper
def with_error_pages_enabled(&block)
context "enabled error pages" do
around(:each) do |example|
begin
ActionDispatch::Request.force_not_local = true
example.call
ensure
ActionDispatch::Request.force_not_local = false
# workaround for rails issue
ActiveRecord::Base.connection.disable_query_cache!
end
end
block.bind(self).call
end
end
end
module RequestExtension
def self.included(klass)
Rails.application.config.consider_all_requests_local = false
klass.class_eval do
# set this to true if you want to get error pages
cattr_accessor :force_not_local
remove_method :local?
def local?
! self.class.force_not_local
end
end
end
end
end
RSpec.configuration.extend ErrorPagesHelperMethods::RspecHelper, :type => :acceptance
ActionDispatch::Request.send(:include, ErrorPagesHelperMethods::RequestExtension)
# encoding: UTF-8
# for acceptance tests using rspec and steak
require "acceptance/acceptance_helper"
ApplicationController.class_eval do
before_filter :test_error
def test_error
if params[:test_error] == 'internal'
raise "testing error"
elsif params[:test_error] == 'RecordNotFound'
raise ActiveRecord::RecordNotFound
elsif params[:test_error] == 'AccessDenied'
raise AccessDenied
elsif params[:test_error] == 'ResourceGone'
raise ResourceGone
end
end
end
feature "errors" do
with_error_pages_enabled do
scenario "visiting page that doesn't exist" do
visit "http://www.doorkeeperhq.com/foobar"
page.status_code.should == 404
page.find("#main h1").text.should == "The page you were looking for doesn't exist."
page.find("title").text.should match("404")
end
scenario "visiting page that doesn't exist with non-standard format" do
visit "http://www.doorkeeperhq.com/foobar.gif"
page.status_code.should == 404
end
scenario "visiting page with internal error" do
visit "http://www.doorkeeperhq.com/?test_error=internal"
page.status_code.should == 500
page.find("#main h1").text.should == "We're sorry, but something went wrong."
page.find("title").text.should match("500")
end
scenario "visiting page with record not found" do
visit "http://www.doorkeeperhq.com/?test_error=RecordNotFound"
page.status_code.should == 404
page.find("#main h1").text.should == "The page you were looking for doesn't exist."
page.find("title").text.should match("404")
end
scenario "visiting page with AccessDenied" do
visit "http://www.doorkeeperhq.com/?test_error=AccessDenied"
page.status_code.should == 403
page.find("#main h1").text.should == "We're sorry, but you don't have access to this resource."
page.find("title").text.should match("403")
end
scenario "visiting page with ResourceGone" do
visit "http://www.doorkeeperhq.com/?test_error=ResourceGone"
page.status_code.should == 410
page.find("#main h1").text.should == "We're sorry, but this resource no longer exists."
page.find("title").text.should match("410")
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment