方法
實體公用方法
rescue_from(*klasses, with: nil, &block) 連結
註冊例外類別與要被 rescue_with_handler
呼叫的處理常式。
rescue_from
會接收到一系列例外類別或類別名稱,以及由尾端 :with
選項(包含一個方法名稱或 Proc 物件)指定的例外處理常式。或者,也可以提供一個區塊作為處理常式。
使用一個引數的處理常式將會帶有例外作為引數被呼叫,如此一來,在處理時可以檢查例外。
處理常式會被繼承。處理常式由右至左、由下至上,並在階層上搜尋。對於最先滿足 exception.is_a?(klass)
條件的類別,其處理常式(若有)會被呼叫。
class ApplicationController < ActionController::Base
rescue_from User::NotAuthorized, with: :deny_access
rescue_from ActiveRecord::RecordInvalid, with: :show_record_errors
rescue_from "MyApp::BaseError" do |exception|
redirect_to root_url, alert: exception.message
end
private
def deny_access
head :forbidden
end
def show_record_errors(exception)
redirect_back_or_to root_url, alert: exception.record.errors.full_messages.to_sentence
end
end
在例外處理常式內引發的例外不會往上傳遞。
# File activesupport/lib/active_support/rescuable.rb, line 53 def rescue_from(*klasses, with: nil, &block) unless with if block_given? with = block else raise ArgumentError, "Need a handler. Pass the with: keyword argument or provide a block." end end klasses.each do |klass| key = if klass.is_a?(Module) && klass.respond_to?(:===) klass.name elsif klass.is_a?(String) klass else raise ArgumentError, "#{klass.inspect} must be an Exception class or a String referencing an Exception class" end # Put the new handler at the end because the list is read in reverse. self.rescue_handlers += [[key, with]] end end
rescue_with_handler(exception, object: self, visited_exceptions: []) 連結
根據例外類別,將例外與處理常式配對。
如果沒有處理常式與例外配對,程式碼會檢查是否存在與(選用的)exception.cause
配對的處理常式。如果沒有處理常式與例外或其原因配對,程式碼會傳回 nil
,讓你可以處理未處理的例外。如果你有這樣的預期,請務必重新引發未處理的例外。
begin
# ...
rescue => exception
rescue_with_handler(exception) || raise
end
如果例外已處理,則傳回例外,否則傳回 nil
。
# File activesupport/lib/active_support/rescuable.rb, line 90 def rescue_with_handler(exception, object: self, visited_exceptions: []) visited_exceptions << exception if handler = handler_for_rescue(exception, object: object) handler.call exception exception elsif exception if visited_exceptions.include?(exception.cause) nil else rescue_with_handler(exception.cause, object: object, visited_exceptions: visited_exceptions) end end end