One of the most under-appreciated and misunderstood features of both Java and Ruby is exception handling. Most people seem to think that exception handling is only for errors, or even isolated to runtime errors. This is so far from the truth. Exceptions are a gift from the programming gods (Gosling, Matz, you choose). It's an entire sub-system that adds a whole other dimension to execution flow.
Have you ever thought to yourself, "man, it would be so bitchin if this method could conditionally return output or an error if this validation fails"? Or maybe "I'll just return nil if there is a problem". That's what exceptions are for! Huh, oh, wha, wait?....That's right!
Let's talk about what we can do with this. The common way to check that a user is logged in to a Ruby on Rails app is through a callback.
do some checkin...
This works great. However there are times where the authorization has to happen within an action, or possibly the model.
Here's an example. You have some blog software and you want to check to make sure a user has rights to edit a blog entry before you save it. First I'll create the actual exception object.
class Unauthorized < Exception
As you can see this is just a regular class that extends Exception. Save this as unauthorized.rb in the helpers directory. Next I'm going to add the security check to the User model.
unless id == object.user_id
The raise method says, "If the user_id field of this entry doesn't match the current user's id, stop processing and send this exception back up the stack". We'll see where it goes in a minute. So now we should put this to use.
@entry = Entry.find(params[:id])
At this point we have to find the entry so that we can check to see if the user can modify it. If not, the execution will break right before the save call, and here's where it goes.
redirect_to :controller => 'auth', :action => 'unauthorized'
If the exception is raised, it will bubble up until something catches it. This method can be placed in the application controller to trap it and handle it however you need to. The exception can be raised anywhere and it will be handled appropriately. If the Exception is not of type Unauthorized, then just delegate to the parent and behave normally.
This is just a simple example of what can be done with Exceptions. There are so many possibilities. I use it in a shipping calculator to notify the view layer if there was a problem connecting to USPS. I also use it in payment processing if something goes bad.
And don't forget that exceptions are object that can have methods and attributes. This means that you can send any kind of data back up with the exception.
So start raizin them exceptions like crazy, it will make you feel better, I promise.