ryah ([info]four) wrote,
@ 2007-07-31 19:59:00
Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Entry tags:merb, projects

Controller Exceptions in Merb
Since Merb has the lovely property of rendering the output of an action, using ruby-level exceptions to render error pages in Merb could be a cute way to approach error handling.

Suppose one has an action for editing a product which you would like to restrict to administrators:

  def edit
    raise AdminAccessReqired unless session[:user] and session[:user].admin?
    @product = Product.find(params[:id])
    raise UnknownProduct if @product.nil?
    render
  end
Where AdminAccessReqired and UnknownProduct are ControllerExceptions.

The controller exception hierarchy would be rooted with the base class, Merb::ControllerException. The Merb dispatcher would rescue any exception which was a kind_of ControllerException. Derived from ControllerException would be an exception for each of the HTTP error codes. For example:
  module ControllerExceptions
    
    class Unauthorized < ControllerException
      STATUS_CODE = 401
      # ...
    
    class Forbidden < ControllerException  
      STATUS_CODE = 403
      # ...
    
    class NotFound < ControllerException  
      STATUS_CODE = 404
      # ...
Application authors could place addition derivations into dist/app/exceptions. These must be children of an already defined Merb controller exception class. The user defined exceptions would have a method called action which acts like typical controller action. It is called to render a page when the exception is raised. For example
  # dist/app/exceptions/admin_access_required.rb
  class AdminAccessRequired < Merb::ControllerExceptions::Unauthorized
    def action
      if session[:user].nil?
        redirect '/login'
      else
        render # views/exceptions/admin_access_required.rhtml
      end
    end
  end
If the user is logged in but does not have administrative access, this will render a page describing the problem with the proper HTTP status code 401.

The UnknownProduct exception might look like this:
  # dist/app/exceptions/unknown_product.rb
  class UnknownProduct < Merb::ControllerExceptions::NotFound
    def action
      @id = params[:id]
      render # views/exceptions/unknown_product.rhtml
    end
  end
If passed a bad id, the server will respond with 404 and a page that is specific to missing a product.

The advantages of this scheme are
  • Simplifies controller action definitions by placing exceptional logic elsewhere
  • Eases the conformity to HTTP by returning proper error codes
  • Could allow for before/after filters around a restricted type of exceptions (eg, for logging purposes)
  • Further modularizes testing code: one needs only to check that an action raise a particular exception
The idea is from Robert Hahn

x-posted here



Create an Account
Forgot your login?
Login w/ OpenID
English • Español • Deutsch • Русский…