Есть ли способ перехватить все неуловленные исключения в контроллере рельсов, например:
def delete
schedule_id = params[:scheduleId]
begin
Schedules.delete(schedule_id)
rescue ActiveRecord::RecordNotFound
render :json => "record not found"
rescue ActiveRecord::CatchAll
#Only comes in here if nothing else catches the error
end
render :json => "ok"
end
Спасибо
ruby-on-rails
Neigaard
источник
источник
rescue => e
только в блоке?Вы также можете определить метод rescue_from.
class ApplicationController < ActionController::Base rescue_from ActionController::RoutingError, :with => :error_render_method def error_render_method respond_to do |type| type.xml { render :template => "errors/error_404", :status => 404 } type.all { render :nothing => true, :status => 404 } end true end end
В зависимости от того, какова ваша цель, вы также можете рассмотреть возможность НЕ обрабатывать исключения для каждого контроллера. Вместо этого следует использовать что - то вроде exception_handler драгоценного камня , чтобы управлять ответы на исключения последовательно. В качестве бонуса этот подход также будет обрабатывать исключения, возникающие на уровне промежуточного программного обеспечения, такие как синтаксический анализ запросов или ошибки подключения к базе данных, которые ваше приложение не видит. Также может быть интересен гем exception_notifier .
источник
rescue_from Exception
? Насколько я понимаю, лучше от спасенияStandardError
, чтоб вродеSyntaxError
иLoadError
не ловились.Вы можете поймать исключения по типу:
rescue_from ::ActiveRecord::RecordNotFound, with: :record_not_found rescue_from ::NameError, with: :error_occurred rescue_from ::ActionController::RoutingError, with: :error_occurred # Don't resuce from Exception as it will resuce from everything as mentioned here "http://stackoverflow.com/questions/10048173/why-is-it-bad-style-to-rescue-exception-e-in-ruby" Thanks for @Thibaut Barrère for mention that # rescue_from ::Exception, with: :error_occurred protected def record_not_found(exception) render json: {error: exception.message}.to_json, status: 404 return end def error_occurred(exception) render json: {error: exception.message}.to_json, status: 500 return end
источник
Exception
напрямую; см. stackoverflow.com/questions/10048173/…rescue
без аргументов спасет любую ошибку.Итак, вам нужно:
def delete schedule_id = params[:scheduleId] begin Schedules.delete(schedule_id) rescue ActiveRecord::RecordNotFound render :json => "record not found" rescue #Only comes in here if nothing else catches the error end render :json => "ok" end
источник
На самом деле, если вы действительно хотите все уловить , вы просто создаете свое собственное приложение для исключений, которое позволяет вам настраивать поведение, которое обычно обрабатывается промежуточным программным обеспечением PublicExceptions: https://github.com/rails/rails/blob/4-2 -стабильный / Actionpack / lib / action_dispatch / промежуточное ПО / public_exceptions.rb
В куче других ответов есть драгоценные камни, которые делают это за вас, но на самом деле нет причин, по которым вы не можете просто посмотреть на них и сделать это самостоятельно.
Предупреждение: убедитесь, что вы никогда не вызываете исключение в своем обработчике исключений. В противном случае вы получите уродливый FAILSAFE_RESPONSE https://github.com/rails/rails/blob/4-2-stable/actionpack/lib/action_dispatch/middleware/show_exceptions.rb#L4-L22
Кстати, поведение контроллера исходит от спасаемого: https://github.com/rails/rails/blob/4-2-stable/activesupport/lib/active_support/rescuable.rb#L32-L51
источник
Обработка ошибок для более приятного взаимодействия с пользователем - очень сложная задача для правильного выполнения.
Здесь я предоставил полный шаблон, чтобы облегчить вам жизнь. Это лучше, чем драгоценный камень, потому что он полностью настраивается для вашего приложения.
Примечание. Вы можете просмотреть последнюю версию этого шаблона в любое время на моем веб-сайте: https://westonganger.com/posts/how-to-properly-implement-error-exception-handling-for-your-rails-controllers
Контроллер
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 # if sanitized_status_number == 404 # val = false # end # if exception.class == ActionController::InvalidAuthenticityToken # val = false # end 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 ### Log Error logger.error exception exception.backtrace.each do |line| logger.error line end if Rails.env.development? ### To allow for the our development debugging tools raise exception end ### Handle XHR Requests 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 ### Determine URL 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 ### Handle Redirect Based on Request Format 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
Тестирование
Чтобы проверить это в своих спецификациях, вы можете использовать следующий шаблон:
feature 'Error Handling', type: :controller do ### Create anonymous controller, the anonymous controller will inherit from stated controller 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 ### draw routes required for non-CRUD actions 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 ### Enable this to actually render views if you need to validate contents 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
источник