Skip to content
This repository
Browse code

Add an ExceptionWrapper that wraps an exception and provide convenien…

…ce helpers.
  • Loading branch information...
commit 0b677b18ff75cd4bf8fd0b2f9579cd84ca3dc2b1 1 parent b4359bc
José Valim authored December 01, 2011
2  actionpack/lib/action_controller/log_subscriber.rb
@@ -20,7 +20,7 @@ def process_action(event)
20 20
 
21 21
       status = payload[:status]
22 22
       if status.nil? && payload[:exception].present?
23  
-        status = Rack::Utils.status_code(ActionDispatch::ShowExceptions.rescue_responses[payload[:exception].first]) rescue nil
  23
+        status = Rack::Utils.status_code(ActionDispatch::ExceptionWrapper.new({}, payload[:exception]).status_code)
24 24
       end
25 25
       message = "Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in %.0fms" % event.duration
26 26
       message << " (#{additions.join(" | ")})" unless additions.blank?
1  actionpack/lib/action_dispatch.rb
@@ -51,6 +51,7 @@ module ActionDispatch
51 51
     autoload :BestStandardsSupport
52 52
     autoload :Callbacks
53 53
     autoload :Cookies
  54
+    autoload :ExceptionWrapper
54 55
     autoload :Flash
55 56
     autoload :Head
56 57
     autoload :ParamsParser
77  actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
... ...
@@ -0,0 +1,77 @@
  1
+require 'active_support/core_ext/exception'
  2
+
  3
+module ActionDispatch
  4
+  class ExceptionWrapper
  5
+    cattr_accessor :rescue_responses
  6
+    @@rescue_responses = Hash.new(:internal_server_error)
  7
+    @@rescue_responses.merge!(
  8
+      'ActionController::RoutingError'             => :not_found,
  9
+      'AbstractController::ActionNotFound'         => :not_found,
  10
+      'ActionController::MethodNotAllowed'         => :method_not_allowed,
  11
+      'ActionController::NotImplemented'           => :not_implemented,
  12
+      'ActionController::InvalidAuthenticityToken' => :unprocessable_entity
  13
+    )
  14
+
  15
+    cattr_accessor :rescue_templates
  16
+    @@rescue_templates = Hash.new('diagnostics')
  17
+    @@rescue_templates.merge!(
  18
+      'ActionView::MissingTemplate'         => 'missing_template',
  19
+      'ActionController::RoutingError'      => 'routing_error',
  20
+      'AbstractController::ActionNotFound'  => 'unknown_action',
  21
+      'ActionView::Template::Error'         => 'template_error'
  22
+    )
  23
+
  24
+    attr_reader :env, :exception
  25
+
  26
+    def initialize(env, exception)
  27
+      @env = env
  28
+      @exception = original_exception(exception)
  29
+    end
  30
+
  31
+    def rescue_template
  32
+      @@rescue_templates[@exception.class.name]
  33
+    end
  34
+
  35
+    def status_code
  36
+      Rack::Utils.status_code(@@rescue_responses[@exception.class.name])
  37
+    end
  38
+
  39
+    def application_trace
  40
+      clean_backtrace(:silent)
  41
+    end
  42
+
  43
+    def framework_trace
  44
+      clean_backtrace(:noise)
  45
+    end
  46
+
  47
+    def full_trace
  48
+      clean_backtrace(:all)
  49
+    end
  50
+
  51
+    private
  52
+
  53
+    def original_exception(exception)
  54
+      if registered_original_exception?(exception)
  55
+        exception.original_exception
  56
+      else
  57
+        exception
  58
+      end
  59
+    end
  60
+
  61
+    def registered_original_exception?(exception)
  62
+      exception.respond_to?(:original_exception) && @@rescue_responses.has_key?(exception.original_exception.class.name)
  63
+    end
  64
+
  65
+    def clean_backtrace(*args)
  66
+      if backtrace_cleaner
  67
+        backtrace_cleaner.clean(@exception.backtrace, *args)
  68
+      else
  69
+        @exception.backtrace
  70
+      end
  71
+    end
  72
+
  73
+    def backtrace_cleaner
  74
+      @backtrace_cleaner ||= @env['action_dispatch.backtrace_cleaner']
  75
+    end
  76
+  end
  77
+end
97  actionpack/lib/action_dispatch/middleware/show_exceptions.rb
... ...
@@ -1,7 +1,6 @@
1  
-require 'active_support/core_ext/exception'
2 1
 require 'action_controller/metal/exceptions'
3  
-require 'active_support/notifications'
4 2
 require 'action_dispatch/http/request'
  3
+require 'action_dispatch/middleware/exception_wrapper'
5 4
 require 'active_support/deprecation'
6 5
 
7 6
 module ActionDispatch
@@ -10,25 +9,6 @@ module ActionDispatch
10 9
   class ShowExceptions
11 10
     RESCUES_TEMPLATE_PATH = File.join(File.dirname(__FILE__), 'templates')
12 11
 
13  
-    cattr_accessor :rescue_responses
14  
-    @@rescue_responses = Hash.new(:internal_server_error)
15  
-    @@rescue_responses.merge!(
16  
-      'ActionController::RoutingError'             => :not_found,
17  
-      'AbstractController::ActionNotFound'         => :not_found,
18  
-      'ActionController::MethodNotAllowed'         => :method_not_allowed,
19  
-      'ActionController::NotImplemented'           => :not_implemented,
20  
-      'ActionController::InvalidAuthenticityToken' => :unprocessable_entity
21  
-    )
22  
-
23  
-    cattr_accessor :rescue_templates
24  
-    @@rescue_templates = Hash.new('diagnostics')
25  
-    @@rescue_templates.merge!(
26  
-      'ActionView::MissingTemplate'         => 'missing_template',
27  
-      'ActionController::RoutingError'      => 'routing_error',
28  
-      'AbstractController::ActionNotFound'  => 'unknown_action',
29  
-      'ActionView::Template::Error'         => 'template_error'
30  
-    )
31  
-
32 12
     FAILSAFE_RESPONSE = [500, {'Content-Type' => 'text/html'},
33 13
       ["<html><body><h1>500 Internal Server Error</h1>" <<
34 14
        "If you are the administrator of this website, then please read this web " <<
@@ -59,13 +39,13 @@ def call(env)
59 39
 
60 40
     private
61 41
       def render_exception(env, exception)
62  
-        log_error(env, exception)
63  
-        exception = original_exception(exception)
  42
+        wrapper = ExceptionWrapper.new(env, exception)
  43
+        log_error(env, wrapper)
64 44
 
65 45
         if env['action_dispatch.show_detailed_exceptions'] == true
66  
-          rescue_action_diagnostics(env, exception)
  46
+          rescue_action_diagnostics(wrapper)
67 47
         else
68  
-          rescue_action_error_page(exception)
  48
+          rescue_action_error_page(wrapper)
69 49
         end
70 50
       rescue Exception => failsafe_error
71 51
         $stderr.puts "Error during failsafe response: #{failsafe_error}\n  #{failsafe_error.backtrace * "\n  "}"
@@ -74,17 +54,17 @@ def render_exception(env, exception)
74 54
 
75 55
       # Render detailed diagnostics for unhandled exceptions rescued from
76 56
       # a controller action.
77  
-      def rescue_action_diagnostics(env, exception)
  57
+      def rescue_action_diagnostics(wrapper)
78 58
         template = ActionView::Base.new([RESCUES_TEMPLATE_PATH],
79  
-          :request => Request.new(env),
80  
-          :exception => exception,
81  
-          :application_trace => application_trace(env, exception),
82  
-          :framework_trace => framework_trace(env, exception),
83  
-          :full_trace => full_trace(env, exception)
  59
+          :request => Request.new(wrapper.env),
  60
+          :exception => wrapper.exception,
  61
+          :application_trace => wrapper.application_trace,
  62
+          :framework_trace => wrapper.framework_trace,
  63
+          :full_trace => wrapper.full_trace
84 64
         )
85  
-        file = "rescues/#{@@rescue_templates[exception.class.name]}"
  65
+        file = "rescues/#{wrapper.rescue_template}"
86 66
         body = template.render(:template => file, :layout => 'rescues/layout')
87  
-        render(status_code(exception), body)
  67
+        render(wrapper.status_code, body)
88 68
       end
89 69
 
90 70
       # Attempts to render a static error page based on the
@@ -94,8 +74,8 @@ def rescue_action_diagnostics(env, exception)
94 74
       # it will first attempt to render the file at <tt>public/500.da.html</tt>
95 75
       # then attempt to render <tt>public/500.html</tt>. If none of them exist,
96 76
       # the body of the response will be left empty.
97  
-      def rescue_action_error_page(exception)
98  
-        status = status_code(exception)
  77
+      def rescue_action_error_page(wrapper)
  78
+        status = wrapper.status_code
99 79
         locale_path = "#{public_path}/#{status}.#{I18n.locale}.html" if I18n.locale
100 80
         path = "#{public_path}/#{status}.html"
101 81
 
@@ -108,10 +88,6 @@ def rescue_action_error_page(exception)
108 88
         end
109 89
       end
110 90
 
111  
-      def status_code(exception)
112  
-        Rack::Utils.status_code(@@rescue_responses[exception.class.name])
113  
-      end
114  
-
115 91
       def render(status, body)
116 92
         [status, {'Content-Type' => "text/html; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]]
117 93
       end
@@ -120,53 +96,26 @@ def public_path
120 96
         defined?(Rails.public_path) ? Rails.public_path : 'public_path'
121 97
       end
122 98
 
123  
-      def log_error(env, exception)
124  
-        return unless logger(env)
  99
+      def log_error(env, wrapper)
  100
+        logger = logger(env)
  101
+        return unless logger
  102
+
  103
+        exception = wrapper.exception
125 104
 
126 105
         ActiveSupport::Deprecation.silence do
127 106
           message = "\n#{exception.class} (#{exception.message}):\n"
128 107
           message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
129  
-          message << "  " << application_trace(env, exception).join("\n  ")
130  
-          logger(env).fatal("#{message}\n\n")
  108
+          message << "  " << wrapper.application_trace.join("\n  ")
  109
+          logger.fatal("#{message}\n\n")
131 110
         end
132 111
       end
133 112
 
134  
-      def application_trace(env, exception)
135  
-        clean_backtrace(env, exception, :silent)
136  
-      end
137  
-
138  
-      def framework_trace(env, exception)
139  
-        clean_backtrace(env, exception, :noise)
140  
-      end
141  
-
142  
-      def full_trace(env, exception)
143  
-        clean_backtrace(env, exception, :all)
144  
-      end
145  
-
146  
-      def clean_backtrace(env, exception, *args)
147  
-        env['action_dispatch.backtrace_cleaner'] ?
148  
-          env['action_dispatch.backtrace_cleaner'].clean(exception.backtrace, *args) :
149  
-          exception.backtrace
150  
-      end
151  
-
152 113
       def logger(env)
153 114
         env['action_dispatch.logger'] || stderr_logger
154 115
       end
155 116
 
156 117
       def stderr_logger
157  
-        Logger.new($stderr)
158  
-      end
159  
-
160  
-    def original_exception(exception)
161  
-      if registered_original_exception?(exception)
162  
-        exception.original_exception
163  
-      else
164  
-        exception
  118
+        @stderr_logger ||= Logger.new($stderr)
165 119
       end
166  
-    end
167  
-
168  
-    def registered_original_exception?(exception)
169  
-      exception.respond_to?(:original_exception) && @@rescue_responses.has_key?(exception.original_exception.class.name)
170  
-    end
171 120
   end
172 121
 end
4  actionpack/lib/action_dispatch/railtie.rb
@@ -22,8 +22,8 @@ class Railtie < Rails::Railtie
22 22
       ActionDispatch::Http::URL.tld_length = app.config.action_dispatch.tld_length
23 23
       ActionDispatch::Request.ignore_accept_header = app.config.action_dispatch.ignore_accept_header
24 24
 
25  
-      ActionDispatch::ShowExceptions.rescue_responses.merge!(config.action_dispatch.rescue_responses)
26  
-      ActionDispatch::ShowExceptions.rescue_templates.merge!(config.action_dispatch.rescue_templates)
  25
+      ActionDispatch::ExceptionWrapper.rescue_responses.merge!(config.action_dispatch.rescue_responses)
  26
+      ActionDispatch::ExceptionWrapper.rescue_templates.merge!(config.action_dispatch.rescue_templates)
27 27
 
28 28
       config.action_dispatch.always_write_cookie = Rails.env.development? if config.action_dispatch.always_write_cookie.nil?
29 29
       ActionDispatch::Cookies::CookieJar.always_write_cookie = config.action_dispatch.always_write_cookie

0 notes on commit 0b677b1

Please sign in to comment.
Something went wrong with that request. Please try again.