Error Handling In Ruby On Rails
Contents |
Web Dev @ Microsoft SEO By WooRank Books Courses Screencasts Newsletters Versioning ruby exception handling best practices Shop Forums Advertise Contribute Contact Us Our Story 995kSubscribers 132kFollowers 80kFollowers rails throw exception Ruby Article Ruby Error Handling, Beyond the Basics By Darko Gjorgjievski June 16, 2015 Imagine you're riding
Rails Raise Exception With Message
a bike. Now, imagine the designers of that bike built it so it rides smoothly only on roads without bumps and encountering one would result in the entire
Ruby Raise Exception In Rescue
bicycle breaking! You wouldn't want that, would you? Yet this is how thousands of software developers design their software every single day. They put error handling in as an afterthought, dealing with it only when it's inevitable. The truth is, it's not their fault. Most of the material on this subject is very basic, covering simple begin rescue rails things like raising an error, rescuing it, different error types and…that's about it. This article will attempt to go deeper than that. I assume you're familiar with the basics of error handling (using raise, begin/rescue, what StandardError is, error inheritance). That's the only prerequisite for reading this article. Let's begin. What Did We Do Before Raising/Handling Exceptions? Before exceptions were invented, the primary method of communication that something in the program has failed was through error return codes. As time passed, people looked at ways to clearly distinguish between what their program does and what would happen if it didn't do what it was supposed to (return codes were far from ideal for this purpose) do. Thus, the invention of language constructs like: raise rescue begin/end (Many other languages use different wording, like try/catch or throw, but the idea behind it remains the same.) There are opposing views to using exceptions and error handling in the first place. Some of these points make sense and we'll discus
those solutions. Let me walk you through the possibilities. begin/rescue block begin/rescue blocks are the standard ruby mechanism to deal with exceptions. It might look like this: begin
Ruby Rescue Rethrow
do_something rescue handle_exception end This works nice for exceptions that might happen in rescue = e your code. But what if you want to rescue every occurrence of a specific exception, say a NoPermissionError which rescue exception = e might be raised from your security layer? Clearly you do not want to add a begin/rescue block in all your actions just to render an error message, right? Around filter An around https://www.sitepoint.com/ruby-error-handling-beyond-basics/ filter could be used to catch all those exceptions of a given class. Honestly I haven't used a before filter for this, this idea came to my mind when writing this blog post. class ApplicationController < ActionController::Base around_action :handle_exceptions private def handle_exceptions begin yield rescue NoPermissionError redirect_to 'permission_error' end end end rescue_from rescue_from gives you the same possibilities as the https://blog.simplificator.com/2015/03/13/handling-errors-in-ruby-on-rails/ around filter. It's just shorter and easier to read and if the framework offers a convenient way, then why not use it. There are multiple ways to define a handler for an exception, for a short and sweet handler I prefer the block syntax: class ApplicationController < ActionController::Base rescue_from 'NoPermissionError' do |exception| redirect_to 'permission_error' end end exceptions_app There is an additional feature (added in Rails 3.2) that allows to handle exceptions. You can specify an exceptions_app which is used to handle errors. You can use your own Rails app for this: config.exceptions_app = self.routes If you do so, then your routing must be configured to match error codes like so: match '/404', to: 'exceptions#handle_404' ... Alternatively you can specify a lambda which receives the whole Rack env: config.exceptions_app = lambda do |env| # do something end Do you wonder how you can call an arbitrary action when you have the env? It's pretty easy: action = ExceptionsController.action(:render_error) action.call(env) In any case you want to set following configuration for exceptions_app to be used: Rails.application.config.consider_all_requests_local = false Rails.application.config.action_dispatch.show_exceptions = true But where is the exception you ask? It is stored in the Rack env: env[