Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #9449: action_controller_exception_handler.diff

File action_controller_exception_handler.diff, 5.3 kB (added by norbert, 1 year ago)
  • actionpack/test/controller/rescue_test.rb

    old new  
    33uses_mocha 'rescue' do 
    44 
    55class RescueController < ActionController::Base 
     6  class HandledException < StandardError 
     7  end 
     8  handle_exception HandledException, :with => :exception_handler 
     9 
    610  def raises 
    711    render :text => 'already rendered' 
    812    raise "don't panic!" 
     
    1721  end 
    1822   
    1923  def missing_template; end 
     24 
     25  def handled_exception 
     26    raise HandledException 
     27  end 
     28 
     29  protected 
     30    def exception_handler 
     31      render :text => 'exception handled' 
     32    end 
    2033end 
    2134 
    22  
    2335class RescueTest < Test::Unit::TestCase 
    2436  FIXTURE_PUBLIC = "#{File.dirname(__FILE__)}/../fixtures".freeze 
    2537 
     
    3850    end 
    3951  end 
    4052 
    41  
    4253  def test_rescue_action_locally_if_all_requests_local 
    4354    @controller.expects(:local_request?).never 
    4455    @controller.expects(:rescue_action_locally).with(@exception) 
     
    6980    end 
    7081  end 
    7182 
    72  
    7383  def test_rescue_action_in_public_with_error_file 
    7484    with_rails_root FIXTURE_PUBLIC do 
    7585      with_all_requests_local false do 
     
    93103    assert_equal ' ', @response.body 
    94104  end 
    95105 
    96  
    97106  def test_rescue_unknown_action_in_public_with_error_file 
    98107    with_rails_root FIXTURE_PUBLIC do 
    99108      with_all_requests_local false do 
     
    117126    assert_equal ' ', @response.body 
    118127  end 
    119128 
    120  
    121129  def test_rescue_missing_template_in_public 
    122130    with_rails_root FIXTURE_PUBLIC do 
    123131      with_all_requests_local true do 
     
    129137    assert @response.body.include?('missing_template'), "Response should include the template name." 
    130138  end 
    131139 
    132  
    133140  def test_rescue_action_locally 
    134141    get :raises 
    135142    assert_response :internal_server_error 
     
    138145    assert @response.body.include?("don't panic"), "Response should include exception message." 
    139146  end 
    140147 
    141  
    142148  def test_local_request_when_remote_addr_is_localhost 
    143149    @controller.expects(:request).returns(@request).at_least_once 
    144150    with_remote_addr '127.0.0.1' do 
     
    153159    end 
    154160  end 
    155161 
    156  
    157162  def test_rescue_responses 
    158163    responses = ActionController::Base.rescue_responses 
    159164 
     
    182187    assert_equal 'template_error',    templates[ActionView::TemplateError.name] 
    183188  end 
    184189 
    185  
    186190  def test_clean_backtrace 
    187191    with_rails_root nil do 
    188192      # No action if RAILS_ROOT isn't set. 
     
    217221    assert_equal "GET, HEAD, PUT", @response.headers['Allow'] 
    218222  end 
    219223 
     224  def test_handled_exception 
     225    @controller.expects(:rescue_action).never 
     226    get :handled_exception 
     227    assert_response :success 
     228    assert_equal "exception handled", @response.body 
     229  end 
     230 
    220231  protected 
    221232    def with_all_requests_local(local = true) 
    222233      old_local, ActionController::Base.consider_all_requests_local = 
  • actionpack/lib/action_controller/rescue.rb

    old new  
    5050      def process_with_exception(request, response, exception) 
    5151        new.process(request, response, :rescue_action, exception) 
    5252      end 
     53 
     54      # Handle exceptions raised in controller actions by passing at least one exception class and a :with option (as symbol or string) that contains the name of the method to be called to deal with the exception. 
     55      # 
     56      # class ApplicationController < ActionController::Base 
     57      #   handle_exception User::NotAuthorized, :with => :not_authorized # self defined exception 
     58      #   handle_exception ActiveRecord::RecordNotFound, :with => :not_found 
     59      # 
     60      #   protected 
     61      #     def not_authorized 
     62      #       ... 
     63      #     end 
     64      # 
     65      #     def not_found 
     66      #       ... 
     67      #     end 
     68      # end 
     69      def handle_exception(*klasses) 
     70        options = klasses.extract_options! 
     71        unless handler = options[:with] 
     72          raise ArgumentError, "Need a handler. Supply an options hash that has a :with key as the last argument." 
     73        end 
     74 
     75        klasses.each do |klass| 
     76          write_inheritable_hash(:handled_exceptions, klass => handler) 
     77        end 
     78      end 
     79 
     80      def exception_handler_for(klass) #:nodoc: 
     81        (read_inheritable_attribute(:handled_exceptions) || {})[klass] 
     82      end 
    5383    end 
    5484 
    5585    protected 
     
    86116        end 
    87117      end 
    88118 
    89  
    90119      # Overwrite to implement public exception handling (for requests answering false to <tt>local_request?</tt>).  By 
    91120      # default will call render_optional_error_file.  Override this method to provide more user friendly error messages.s 
    92121      def rescue_action_in_public(exception) #:doc: 
     
    132161      def perform_action_with_rescue #:nodoc: 
    133162        perform_action_without_rescue 
    134163      rescue Exception => exception  # errors from action performed 
    135         rescue_action(exception) 
     164        handle_exception_or_rescue_action(exception) 
    136165      end 
    137166 
    138167      def rescues_path(template_name) 
     
    156185          end 
    157186        end 
    158187      end 
     188 
     189      def handle_exception_or_rescue_action(exception) 
     190        if handler = self.class.exception_handler_for(exception.class) 
     191          send(handler) 
     192        else 
     193          rescue_action(exception) 
     194        end 
     195      end 
    159196  end 
    160197end