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