Daha iyi bir kullanıcı deneyimi için hata yönetimi, doğru şekilde çekilmesi çok zor bir şeydir.
Burada, hayatınızı kolaylaştırmak için eksiksiz bir şablon sağladım. Bu bir mücevherden daha iyidir çünkü uygulamanıza göre tamamen özelleştirilebilir.
Not: Bu şablonun en son sürümünü web sitemde istediğiniz zaman görüntüleyebilirsiniz: https://westonganger.com/posts/how-to-properly-implement-error-exception-handling-for-your-rails-controllers
Kontrolör
class ApplicationController < ActiveRecord::Base
def is_admin_path?
request.path.split("/").reject{|x| x.blank?}.first == 'admin'
end
private
def send_error_report(exception, sanitized_status_number)
val = true
return val
end
def get_exception_status_number(exception)
status_number = 500
error_classes_404 = [
ActiveRecord::RecordNotFound,
ActionController::RoutingError,
]
if error_classes_404.include?(exception.class)
if current_user
status_number = 500
else
status_number = 404
end
end
return status_number.to_i
end
def perform_error_redirect(exception, error_message:)
status_number = get_exception_status_number(exception)
if send_error_report(exception, status_number)
ExceptionNotifier.notify_exception(exception, data: {status: status_number})
end
logger.error exception
exception.backtrace.each do |line|
logger.error line
end
if Rails.env.development?
raise exception
end
if (request.format.html? && request.xhr?)
render template: "/errors/#{status_number}.html.erb", status: status_number
return
end
if status_number == 404
if request.format.html?
if request.get?
render template: "/errors/#{status_number}.html.erb", status: status_number
return
else
redirect_to "/#{status_number}"
end
else
head status_number
end
return
end
if request.referrer.present?
url = request.referrer
else
if current_user && is_admin_path? && request.path.gsub("/","") != admin_root_path.gsub("/","")
url = admin_root_path
elsif request.path != "/"
url = "/"
else
if request.format.html?
if request.get?
render template: "/errors/500.html.erb", status: 500
else
redirect_to "/500"
end
else
head 500
end
return
end
end
flash_message = error_message
if request.format.html?
redirect_to url, alert: flash_message
elsif request.format.js?
flash[:alert] = flash_message
flash.keep(:alert)
render js: "window.location = '#{url}';"
else
head status_number
end
end
rescue_from Exception do |exception|
perform_error_redirect(exception, error_message: I18n.t('errors.system.general'))
end
end
Test yapmak
Bunu spesifikasyonlarınızda test etmek için aşağıdaki şablonu kullanabilirsiniz:
feature 'Error Handling', type: :controller do
controller(ApplicationController) do
def raise_500
raise Errors::InvalidBehaviour.new("foobar")
end
def raise_possible_404
raise ActiveRecord::RecordNotFound
end
end
before(:all) do
@user = User.first
@error_500 = I18n.t('errors.system.general')
@error_404 = I18n.t('errors.system.not_found')
end
after(:all) do
Rails.application.reload_routes!
end
before :each do
routes.draw do
get '/anonymous/raise_500'
get '/anonymous/raise_possible_404'
end
end
describe "General Errors" do
context "Request Format: 'html'" do
scenario 'xhr request' do
get :raise_500, format: :html, xhr: true
expect(response).to render_template('errors/500.html.erb')
end
scenario 'with referrer' do
path = "/foobar"
request.env["HTTP_REFERER"] = path
get :raise_500
expect(response).to redirect_to(path)
post :raise_500
expect(response).to redirect_to(path)
end
scenario 'admin sub page' do
sign_in @user
request.path_info = "/admin/foobar"
get :raise_500
expect(response).to redirect_to(admin_root_path)
post :raise_500
expect(response).to redirect_to(admin_root_path)
end
scenario "admin root" do
sign_in @user
request.path_info = "/admin"
get :raise_500
expect(response).to redirect_to("/")
post :raise_500
expect(response).to redirect_to("/")
end
scenario 'public sub-page' do
get :raise_500
expect(response).to redirect_to("/")
post :raise_500
expect(response).to redirect_to("/")
end
scenario 'public root' do
request.path_info = "/"
get :raise_500
expect(response).to render_template('errors/500.html.erb')
expect(response).to have_http_status(500)
post :raise_500
expect(response).to redirect_to("/500")
end
scenario '404 error' do
get :raise_possible_404
expect(response).to render_template('errors/404.html.erb')
expect(response).to have_http_status(404)
post :raise_possible_404
expect(response).to redirect_to('/404')
sign_in @user
get :raise_possible_404
expect(response).to redirect_to('/')
post :raise_possible_404
expect(response).to redirect_to('/')
end
end
context "Request Format: 'js'" do
render_views
scenario 'xhr request' do
get :raise_500, format: :js, xhr: true
expect(response.body).to include("window.location = '/';")
post :raise_500, format: :js, xhr: true
expect(response.body).to include("window.location = '/';")
end
scenario 'with referrer' do
path = "/foobar"
request.env["HTTP_REFERER"] = path
get :raise_500, format: :js
expect(response.body).to include("window.location = '#{path}';")
post :raise_500, format: :js
expect(response.body).to include("window.location = '#{path}';")
end
scenario 'admin sub page' do
sign_in @user
request.path_info = "/admin/foobar"
get :raise_500, format: :js
expect(response.body).to include("window.location = '#{admin_root_path}';")
post :raise_500, format: :js
expect(response.body).to include("window.location = '#{admin_root_path}';")
end
scenario "admin root" do
sign_in @user
request.path_info = "/admin"
get :raise_500, format: :js
expect(response.body).to include("window.location = '/';")
post :raise_500, format: :js
expect(response.body).to include("window.location = '/';")
end
scenario 'public page' do
get :raise_500, format: :js
expect(response.body).to include("window.location = '/';")
post :raise_500, format: :js
expect(response.body).to include("window.location = '/';")
end
scenario 'public root' do
request.path_info = "/"
get :raise_500, format: :js
expect(response).to have_http_status(500)
post :raise_500, format: :js
expect(response).to have_http_status(500)
end
scenario '404 error' do
get :raise_possible_404, format: :js
expect(response).to have_http_status(404)
post :raise_possible_404, format: :js
expect(response).to have_http_status(404)
sign_in @user
get :raise_possible_404, format: :js
expect(response).to have_http_status(200)
expect(response.body).to include("window.location = '/';")
post :raise_possible_404, format: :js
expect(response).to have_http_status(200)
expect(response.body).to include("window.location = '/';")
end
end
context "Other Request Format" do
scenario '500 error' do
get :raise_500, format: :json
expect(response).to have_http_status(500)
post :raise_500, format: :json
expect(response).to have_http_status(500)
end
scenario '404 error' do
get :raise_possible_404, format: :json
expect(response).to have_http_status(404)
post :raise_possible_404, format: :json
expect(response).to have_http_status(404)
sign_in @user
get :raise_possible_404, format: :json
expect(response).to have_http_status(500)
post :raise_possible_404, format: :json
expect(response).to have_http_status(500)
end
end
end
end