Czy istnieje sposób na złapanie wszystkich nieobjętych wyjątków w kontrolerze szyn, na przykład:
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
Dziękuję Ci
ruby-on-rails
Neigaard
źródło
źródło
rescue => e
tylko w bloku?Możesz także zdefiniować metodę 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
W zależności od tego, jaki jest twój cel, możesz również rozważyć NIE obsługi wyjątków dla każdego kontrolera. Zamiast używać coś jak exception_handler gem zarządzać odpowiedzi na wyjątkami konsekwentnie. Jako bonus, to podejście będzie obsługiwać również wyjątki, które występują w warstwie oprogramowania pośredniego, takie jak analiza żądań lub błędy połączenia z bazą danych, których aplikacja nie widzi. Exception_notifier klejnot może być również interesujące.
źródło
rescue_from Exception
? Rozumiem, że lepiej jest ratowaćStandardError
, więc takie rzeczy jakSyntaxError
iLoadError
nie są złapane.Możesz łapać wyjątki według typu:
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
źródło
Exception
bezpośrednio; patrz stackoverflow.com/questions/10048173/…rescue
bez argumentów uratuje każdy błąd.Więc będziesz chciał:
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
źródło
Właściwie, jeśli naprawdę chcesz złapać wszystko , po prostu utwórz własną aplikację wyjątków, która pozwoli ci dostosować zachowanie, które jest zwykle obsługiwane przez oprogramowanie pośredniczące PublicExceptions: https://github.com/rails/rails/blob/4-2 -stable / actionpack / lib / action_dispatch / middleware / public_exceptions.rb
Kilka innych odpowiedzi ma takie same klejnoty, które robią to za Ciebie, ale tak naprawdę nie ma powodu, dla którego nie możesz po prostu na nie spojrzeć i zrobić tego samodzielnie.
Ostrzeżenie: upewnij się, że nigdy nie zgłosisz wyjątku w programie obsługi wyjątków. W przeciwnym razie otrzymasz brzydką odpowiedź FAILSAFE_RESPONSE https://github.com/rails/rails/blob/4-2-stable/actionpack/lib/action_dispatch/middleware/show_exceptions.rb#L4-L22
BTW, zachowanie w kontrolerze pochodzi z ratunku: https://github.com/rails/rails/blob/4-2-stable/activesupport/lib/active_support/rescuable.rb#L32-L51
źródło
Obsługa błędów w celu zapewnienia przyjemniejszego użytkowania jest bardzo trudna do poprawnego wykonania.
Tutaj dostarczyłem w pełni kompletny szablon, aby ułatwić Ci życie. To jest lepsze niż klejnot, ponieważ można go w pełni dostosować do Twojej aplikacji.
Uwaga: najnowszą wersję tego szablonu możesz w każdej chwili wyświetlić na mojej stronie internetowej: 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
Testowanie
Aby przetestować to w swoich specyfikacjach, możesz użyć następującego szablonu:
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
źródło