HasFinder — It’s Now Easier than ever to create complex, re-usable SQL queries

September 2, 2007 Pivotal Labs

HasFinder is an extension to ActiveRecord that makes it easier than ever to create custom find and count queries.

Let’s start with an example. Suppose you have an Article model; some articles are published, some are popular. Let’s declare finders for each of these notions. You may be tempted to write something like the following:

class Article < ActiveRecord::Base
  def self.published
    find(:all, :conditions => {:published => true})

  def self.popular

But there are serious limitations to this approach. How do you find articles that are BOTH popular and published? How can you easily paginate published articles?

HasFinder Features

Let’s define the equivalent finders using my new plugin, has_finder:

class Article < ActiveRecord::Base
  has_finder :published, :conditions => {:published => true}
  has_finder :popular, :conditions => ...

Query Composition

Now, you can elegantly compose queries:


This will return all articles that are both popular and published.

Calculations and Nested Finds

You can also easily paginate or call nested finders or do calculations:

Article.published.paginate(:page => 1)
Article.popular.find(:all, :conditions => {...})

Works with ActiveRecord has_many and has_many :through Associations

Furthermore, without any additional work, these finders will work with ActiveRecord associations.

class User
  has_many :articles


Finders are extendable just like ActiveRecord Associations

class Article
  has_finder :unpublished :conditions => {:published => false} do
    def published_all

Alternatively, you can use the :extend options:

class Article
  has_finder :unpublished, :conditions => ..., :extend => MyExtensionModule

Finders behave just like ActiveRecord Associations

For example, you can call #reload:


Finders can take parameters

class Car
  has_finder :colored, lambda {|color| { :conditions => {:color => color} } }

Car.colored('red').paginate(:page => 1)

What makes HasFinder better than alternatives like scope_out and scoped_proxy?

There are already two plugins similar to HasFinder: scope_out and scoped_proxy. Both of them are excellent. In fact, Scoped Proxy was the model for HasFinder. Unfortunately, neither plugin provided all of the features I desired. Scope-Out lacks on-the-fly composition, a nice way to call a nested find, or the ability to do arbitrary calculations. Scoped Proxy is great, but it doesn’t work with regular ActiveRecord Associations, it is not extendable like ActiveRecord associations, and it doesn’t behave exactly like a regular ActiveRecord Association. Neither of them work out of the box with will_paginate. For all of these reasons and more, I rolled my own. It’s now available as a gem.


% gem install has_finder


In environment.rb:

gem 'has_finder'
require 'has_finder'

See the examples above for usage.

About the Author


Ruby quiz du jour
Ruby quiz du jour

Question: In Ruby, what does the following represent? -1.0/0...0 Post your guesses as comments. Answer t...

Ten Things I Hate about Proxy Objects, Part I
Ten Things I Hate about Proxy Objects, Part I

Has Many Through Has Many Through Has Many Through ... In which the author relates several things he hates...