Repository: rails/rails
File: activesupport/lib/active_support/rescuable.rb (Ruby)

Code before:

          # Put the new handler at the end because the list is read in reverse.
          self.rescue_handlers += [[key, with]]
        end
      end

      # Matches an exception to a handler based on the exception class.
      #
      # If no handler matches the exception, check for a handler matching the
      # (optional) +exception.cause+. If no handler matches the exception or its
      # cause, this returns +nil+, so you can deal with unhandled exceptions.
      # Be sure to re-raise unhandled exceptions if this is what you expect.
      #
      #     begin
      #       # ...
      #     rescue => exception
      #       rescue_with_handler(exception) || raise
      #     end
      #
      # Returns the exception if it was handled and +nil+ if it was not.
      def rescue_with_handler(exception, object: self, visited_exceptions: [])
        visited_exceptions << exception

        if handler = handler_for_rescue(exception, object: object)
          handler.call exception
          ActiveSupport::Notifications.instrument("rescue_from_callback.active_support", exception: 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

      def handler_for_rescue(exception, object: self) # :nodoc:
        case rescuer = find_rescue_handler(exception)
        when Symbol
          method = object.method(rescuer)
          if method.arity == 0
            -> e { method.call }
          else
            method
          end
        when Proc
          if rescuer.arity == 0
            -> e { object.instance_exec(&rescuer) }
          else
            -> e { object.instance_exec(e, &rescuer) }
          end

Review comment (suggestion):
```suggestion
          ActiveSupport::Notifications.instrument("rescue_from_callback.action_controller", exception: exception)
```

Code after:

          # Put the new handler at the end because the list is read in reverse.
          self.rescue_handlers += [[key, with]]
        end
      end

      # Matches an exception to a handler based on the exception class.
      #
      # If no handler matches the exception, check for a handler matching the
      # (optional) +exception.cause+. If no handler matches the exception or its
      # cause, this returns +nil+, so you can deal with unhandled exceptions.
      # Be sure to re-raise unhandled exceptions if this is what you expect.
      #
      #     begin
      #       # ...
      #     rescue => exception
      #       rescue_with_handler(exception) || raise
      #     end
      #
      # Returns the exception if it was handled and +nil+ if it was not.
      def rescue_with_handler(exception, object: self, visited_exceptions: [])
        visited_exceptions << exception

        if handler = handler_for_rescue(exception, object: object)
          handler.call exception
          ActiveSupport::Notifications.instrument("rescue_from_callback.action_controller", exception: 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

      def handler_for_rescue(exception, object: self) # :nodoc:
        case rescuer = find_rescue_handler(exception)
        when Symbol
          method = object.method(rescuer)
          if method.arity == 0
            -> e { method.call }
          else
            method
          end
        when Proc
          if rescuer.arity == 0
            -> e { object.instance_exec(&rescuer) }
          else
            -> e { object.instance_exec(e, &rescuer) }
          end