跳至内容 跳至搜索
方法
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