---
title: save bang your head, active record will drive you mad
teaser:
tags: web,rails
author: Jared Carroll
published_on: 2007-09-26
---

So in my never-ending quest to remove conditional logic from code, I began
writing my Rails actions like:

    def create
      @user = User.new params[:user]
      @user.save!
      redirect_to user_path(@user)
    rescue ActiveRecord::RecordNotSaved
      flash[:notice] = 'Unable to create user'
      render :action => :new
    end

Instead of the traditional way using conditional logic like:

    def create
      @user = User.new params[:user]
      if @user.save
        redirect_to user_path(@user)
      else
        flash[:notice] = 'Unable to create user'
        render :action => :new
      end
    end

I did this until one of my co-workers saw this and said:

> exceptions should not be expected

What?

When writing an application you expect invalid input from users.  Since we
expect invalid input we should NOT be handling it via exceptions because
exceptions should only be used for unexpected situations.

Well what's an unexpected situation?

* Losing a connection to your database
* Running out of memory
* Some obscure IO/socket error

Now I'm not going to write error handling for those unexpected circumstances
because I don't expect them to happen.  If they do then I want the user to see
an error page (500) and the developers to be notified via email about the
exception (using exception notifier in Rails) (if i cared then yes I'd have to
write error handling code but trying to recover from situations such as an out
of memory is not going to be easy, if at all possible, so I want my application
to fail in such a rare situation).

Let's look at an example of reading from a file from the pickaxe.

    File.open('testfile') do |file|
      while line = file.gets
        puts line
      end
    end

Now `IO#gets` returns a `String` or `nil`.  That is correct because reaching
the end of the file is NOT an unexpected situation and should be handled with
conditional logic.

What if ruby raised some `EOFError` instead:

    File.open('testfile') do |file|
      while line = file.gets
        puts line
      end
    rescue EOFError
      return
    end

Raising an `EOFError` would mean reaching the end of the file would be
unexpected.  That's crazy talk.

I think `ActiveRecord::Base#save!` and `ActiveRecord::Base.update_attributes!`
should be pulled from the public <abbr title="Application Programming
Interface">API</abbr>.  All they do is save the object and raise an exception if
any validation fails.  I doubt there are any web applications out there that do
NOT expect invalid input.  So there is no point in using `#save!` and
`#update_attributes!` over their true/false equivalents `#save` and
`#update_attributes`.

However, there is one case where they both have to be used.  In transactions.
Apparently the only way to roll back a transaction is to raise an exception.  I
say there should be some #rollback method so you could do something like:

    User.transaction do
     user.save || rollback
     another_user.save || rollback
    end

Following this convention we could also return the '!' back to its original
meaning of 'modifying the receiver'.  Rails, with its `#save!` and
`#update_attributes!`, has pushed the '!' to mean 'something dangerous' in order
to justify the exception raising of methods like `#save!` and
`#update_attributes!`.

Another Ruby idiom that is an abuse of exceptions is something along the lines of:

    user.address.street rescue ''
    # or
    user.address.street rescue nil

Code like this says that an address is optional for a user.  Since a user
without an address is not an exceptional situation it should be handled with
conditional logic instead of exceptions.

    if ! user.address.nil?
      user.address.street
    end

I can't stand that 'rescue nil' hack.  Quit being lazy and write the 'if'
statement.
