跳到內容 跳到搜尋
方法
R

實體公用方法

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