Raising errors in controllers

September 21st, 2007

All the cool people raise errors now in their controllers and models as opposed to using save and checking to see if it returned nil or the object we're dealing with. For example, in the create action, you would having something like this:
1
2
3
4
5
6
7
def create
  @book = Book.new params[:book]
  @book.save!

  flash[:notice] = 'Book was successfully created.'
  redirect_to @book
end
By doing this, you can stick this in your application controller (extracted from Beast):
1
2
3
4
5
6
7
8
  private
    def rescue_action(exception)
      exception.is_a?(ActiveRecord::RecordInvalid) ? render_invalid_record(exception.record) : super
    end
    
    def render_invalid_record(record)
      render :action => (record.new_record? ? 'new' : 'edit')
    end
And any create controller that raises and ActiveRecord::RecordInvalid exception will directly to the new view. The same applies for the update controller:
1
2
3
4
5
6
7
def update
  @book = Book.find params[:id]
  @book.update_attributes! params[:book] 

  flash[:notice] = 'Book was successfully updated.'
  redirect_to @book
end
When a PUT is made, it is sent to the update method in your controller and then book will render to the edit view because of the line of code we stuck in our application controller:

render :action => (record.new_record? ? 'new' : 'edit')
This DRYs up controllers significantly as it gets rid of all the render :action => 'new' and render :action => 'edit' lines I used to see all over my code. Raising exceptions is also good for show, edit, update and destroy actions. By utilizing the find method and supplying it with a single parameter ID, it will raise an ActiveRecord::RecordNotFound exception. In rails edge, it will rescue this exception and automatically redirect to the default 404 page located in public/404.html and give the client the appropriate 404 status. Try it out on your controllers and feel the DRYness!