Raising finders

Written . Tagged Ruby, Ruby on Rails.

I find exceptions preferable to if/else branching in many cases.

Though Rails has save! and create! methods that raise exceptions if they fail, the same can not be said for finders. User.find(123) will raise ActiveRecord::RecordNotFound if there’s no record with that id, but other finders (find(:all, …), find(:first, …) and dynamic finders like find_by_username(…)) will just return nil or an empty array.

Adding this has been discussed, and there is a slumbering ticket.

This is my take. require 'raising_finders' in environment.rb and put this in lib/raising_finders.rb:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Enables methods like find!(:all, …), find_by_username!(…) that
# raise ActiveRecord::RecordNotFound for empty results.

module RaisingFinders
  def method_missing(name, *args)
    return super unless name.to_s =~ /^(find(_.+)?)!$/
    returning send($1, *args) do |result|
      raise ActiveRecord::RecordNotFound if result.blank?
    end
  end
end

class << ActiveRecord::Base
  include RaisingFinders
end

While writing this, I found I was reinventing the wheel – there is a whiny_finder plugin that’s functionally equivalent – but I find that code a bit wordy. My wheel is rounder!