Apakah ada cara untuk menangkap semua pengecualian yang tidak cocok di pengontrol rel, seperti ini:
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
Terima kasih
ruby-on-rails
Neigaard
sumber
sumber
rescue => e
blok saja?Anda juga dapat menentukan metode 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
Bergantung pada apa tujuan Anda, Anda mungkin juga ingin mempertimbangkan untuk TIDAK menangani pengecualian pada basis per-pengontrol. Sebaliknya, gunakan sesuatu seperti permata exception_handler untuk mengelola respons terhadap pengecualian secara konsisten. Sebagai bonus, pendekatan ini juga akan menangani pengecualian yang terjadi pada lapisan middleware, seperti parsing permintaan atau kesalahan koneksi database yang tidak dilihat aplikasi Anda. The exception_notifier permata mungkin juga menarik.
sumber
rescue_from Exception
? Pemahaman saya adalah bahwa lebih baik menyelamatkan dariStandardError
, jadi hal-hal sepertiSyntaxError
danLoadError
tidak tertangkap.Anda dapat menangkap pengecualian berdasarkan jenis:
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
sumber
Exception
secara langsung; lihat stackoverflow.com/questions/10048173/…rescue
tanpa argumen akan menyelamatkan kesalahan apapun.Jadi, Anda pasti menginginkan:
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
sumber
Sebenarnya, jika Anda benar-benar ingin menangkap semuanya , Anda cukup membuat aplikasi pengecualian Anda sendiri, yang memungkinkan Anda menyesuaikan perilaku yang biasanya ditangani oleh middleware PublicExceptions: https://github.com/rails/rails/blob/4-2 -stabil / actionpack / lib / action_dispatch / middleware / public_exceptions.rb
Sekelompok jawaban lain berbagi permata yang melakukan ini untuk Anda, tetapi sebenarnya tidak ada alasan Anda tidak bisa hanya melihatnya dan melakukannya sendiri.
Peringatan: pastikan Anda tidak pernah memunculkan pengecualian di penangan pengecualian Anda. Jika tidak, Anda akan mendapatkan FAILSAFE_RESPONSE yang jelek https://github.com/rails/rails/blob/4-2-stable/actionpack/lib/action_dispatch/middleware/show_exceptions.rb#L4-L22
BTW, perilaku di pengontrol berasal dari rescuable: https://github.com/rails/rails/blob/4-2-stable/activesupport/lib/active_support/rescuable.rb#L32-L51
sumber
Penanganan kesalahan untuk pengalaman pengguna yang lebih baik adalah hal yang sangat sulit untuk dilakukan dengan benar.
Disini saya telah menyediakan template yang lengkap untuk mempermudah hidup Anda. Ini lebih baik daripada permata karena sepenuhnya dapat disesuaikan dengan aplikasi Anda.
Catatan: Anda dapat melihat versi terbaru template ini kapan saja di situs web saya: https://westonganger.com/posts/how-to-properly-implement-error-exception-handling-for-your-rails-controllers
Kontroler
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
Menguji
Untuk mengujinya dalam spesifikasi Anda, Anda dapat menggunakan template berikut:
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
sumber