aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_controller/rescue.rb
diff options
context:
space:
mode:
authorDavid Heinemeier Hansson <david@loudthinking.com>2004-11-24 01:04:44 +0000
committerDavid Heinemeier Hansson <david@loudthinking.com>2004-11-24 01:04:44 +0000
commitdb045dbbf60b53dbe013ef25554fd013baf88134 (patch)
tree257830e3c76458c8ff3d1329de83f32b23926028 /actionpack/lib/action_controller/rescue.rb
downloadrails-db045dbbf60b53dbe013ef25554fd013baf88134.tar.gz
rails-db045dbbf60b53dbe013ef25554fd013baf88134.tar.bz2
rails-db045dbbf60b53dbe013ef25554fd013baf88134.zip
Initial
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@4 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'actionpack/lib/action_controller/rescue.rb')
-rw-r--r--actionpack/lib/action_controller/rescue.rb94
1 files changed, 94 insertions, 0 deletions
diff --git a/actionpack/lib/action_controller/rescue.rb b/actionpack/lib/action_controller/rescue.rb
new file mode 100644
index 0000000000..c0933b2666
--- /dev/null
+++ b/actionpack/lib/action_controller/rescue.rb
@@ -0,0 +1,94 @@
+module ActionController #:nodoc:
+ # Actions that fail to perform as expected throw exceptions. These exceptions can either be rescued for the public view
+ # (with a nice user-friendly explanation) or for the developers view (with tons of debugging information). The developers view
+ # is already implemented by the Action Controller, but the public view should be tailored to your specific application. So too
+ # could the decision on whether something is a public or a developer request.
+ #
+ # You can tailor the rescuing behavior and appearance by overwriting the following two stub methods.
+ module Rescue
+ def self.append_features(base) #:nodoc:
+ super
+ base.class_eval do
+ alias_method :perform_action_without_rescue, :perform_action
+ alias_method :perform_action, :perform_action_with_rescue
+ end
+ end
+
+ protected
+ # Exception handler called when the performance of an action raises an exception.
+ def rescue_action(exception)
+ log_error(exception) unless logger.nil?
+
+ if consider_all_requests_local || local_request?
+ rescue_action_locally(exception)
+ else
+ rescue_action_in_public(exception)
+ end
+ end
+
+ # Overwrite to implement custom logging of errors. By default logs as fatal.
+ def log_error(exception) #:doc:
+ if ActionView::TemplateError === exception
+ logger.fatal(exception.to_s)
+ else
+ logger.fatal(
+ "\n\n#{exception.class} (#{exception.message}):\n " +
+ clean_backtrace(exception).join("\n ") +
+ "\n\n"
+ )
+ end
+ end
+
+ # Overwrite to implement public exception handling (for requests answering false to <tt>local_request?</tt>).
+ def rescue_action_in_public(exception) #:doc:
+ render_text "<html><body><h1>Application error (Rails)</h1></body></html>"
+ end
+
+ # Overwrite to expand the meaning of a local request in order to show local rescues on other occurances than
+ # the remote IP being 127.0.0.1. For example, this could include the IP of the developer machine when debugging
+ # remotely.
+ def local_request? #:doc:
+ @request.remote_addr == "127.0.0.1"
+ end
+
+ # Renders a detailed diagnostics screen on action exceptions.
+ def rescue_action_locally(exception)
+ @exception = exception
+ @rescues_path = File.dirname(__FILE__) + "/templates/rescues/"
+ add_variables_to_assigns
+ @contents = @template.render_file(template_path_for_local_rescue(exception), false)
+
+ @headers["Content-Type"] = "text/html"
+ render_file(rescues_path("layout"), "500 Internal Error")
+ end
+
+ private
+ def perform_action_with_rescue #:nodoc:
+ begin
+ perform_action_without_rescue
+ rescue Exception => exception
+ rescue_action(exception)
+ end
+ end
+
+ def rescues_path(template_name)
+ File.dirname(__FILE__) + "/templates/rescues/#{template_name}.rhtml"
+ end
+
+ def template_path_for_local_rescue(exception)
+ rescues_path(
+ case exception
+ when MissingTemplate then "missing_template"
+ when UnknownAction then "unknown_action"
+ when ActionView::TemplateError then "template_error"
+ else "diagnostics"
+ end
+ )
+ end
+
+ def clean_backtrace(exception)
+ base_dir = File.expand_path(File.dirname(__FILE__) + "/../../../../")
+ exception.backtrace.collect { |line| line.gsub(base_dir, "").gsub("/public/../config/environments/../../", "").gsub("/public/../", "") }
+ end
+ end
+end