I released version 0.5 of this Ruby on Rails plugin a few months ago and have since updated it to include ‘and’ and ‘or’ methods, as well as the ability to use sub-conditions.

Here are some code samples:

  Condition.block { |c|
    c.and "one", 1
    c.and "two", 2
    c.and { |d|
      d.or "three", 3
      d.or "four", 4
    }
  }

# => ["one = ? AND two = ? AND (three = ? OR four = ?)", 1, 2, 3, 4]

Since this uses Ruby’s blocks to construct a Rails condition array, you can use all of Ruby’s familiar logical constructs to achieve cleaner code in some cases. For example:

  Condition.block { |c|
    c.and "user_id", @user_id
    c.and { |d|
      d.or "admin", true
      d.or "joined_at", "<", Date.new(2007, 1, 1)
    } unless @dont_override_user_id
  }

# If @dont_override_user_id is false, then
# => ["user_id = ? AND (admin = ? OR joined_at < ?)", 10, true, Date.new(2007, 1, 1)]
#
# If @dont_override_user_id is true, then
# => ["user_id = ?", 10]

I use this directly in my ActiveRecord queries, like this:

  Book.find(:all,
      :include => {:content_pointer => :invitees},
      :conditions => Condition.block { |c|
        c.and "invitees.user_id", self.id
        c.and "content_pointers.created_by_id", self.id
        c.and "content_pointers.company_id", company.id if company
      })

Note: You may get some unexpected results if you try mixing ‘and’ and ‘or’ within the same block. The current implementation assumes that you will be consistent, and use a new block whenever you wish to switch logical operators. As an example, don’t do this:

Condition.block { |c|
  c.and "user_id", 1
  c.and "book_id", 2
  c.or "company_id", 3
}
# BAD
# Output will be: ["user_id = ? OR book_id = ? OR company_id = ?", 1, 2, 3]

# Do this instead:
Condition.block { |c|
  c.and "user_id", 1
  c.and { |d|
    d.or "book_id", 2
    d.or "company_id", 3
  }
}
# OK
# Output will be: ["user_id = ? AND (book_id = ? OR company_id = ?)", 1, 2, 3]

The Condition Builder plugin is available as a tar/gz file. Download it here.