Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

conditioner for ActiveRecord-friendly conditions from a collection (See related posts)

I frequently have a collection of values that I want to match in an ActiveRecord query, but it would be nice if I could let ActiveRecord handle checking the data and escaping it properly. So, I wrote this method to return ActiveRecord-friendly conditions, such as:
["user_id=? AND job_id=?", 3, 4]
based on the 'raw' conditions you feed to it, such as:
[['user_id', 3], ['job_id', 4]]


# Returns ActiveRecord-friendly conditions based on the given
# raw conditions; handles grouping based on like field names;
# allows different boolean operators in raw conditions;
# allows different comparison operators in raw conditions;
# raw conditions setup:
# [[field name, desired value, bool. op., comp. op.], ...]
# name = condition[0]
# value = condition[1]
# bool_type = condition[2]
# comparison = condition[3]
# raw conditions example:
# [['type_id', '4', 'OR'], ['created_on', Date.new, 'AND', '<=']]
def conditioner( raw_conditions )
  return nil if raw_conditions.nil? || raw_conditions.empty?
  
  conditions = ['(']
  count = 0
  prev_name = raw_conditions[0][0]
  raw_conditions.each do |condition|
    name = condition[0]
      
    conditions[0] << ') AND ' if prev_name != name
    conditions[0] << ' ' << ( condition[2] || 'OR' ) << ' ' unless count == 0 || prev_name != name
    conditions[0] << '(' if prev_name != name
    conditions[0] << name + ' ' << ( condition[3] || '=' ) + ' ?'
      
    conditions << condition[1]
      
    prev_name = name
    count += 1
  end
  conditions[0] << ')'

  conditions
end


This way, you can do something like the following:
model_ids = Model.find( :all ).map( &:id )
raw_conditions = model_ids.collect { |id| ['model_id', id] }
conditions = conditioner( raw_conditions )
desired_collection = OtherModel.find( :all, :conditions => conditions )


If your query needs to depend on more than one factor, you might do something like the following:
if test
  raw_conditions = [['user_id', 3]]
else
  raw_conditions = [['user_id', 4], ['groups.name', 'dev']]
end

team_ids.each { |id| raw_conditions << ['team_id', id, 'AND'] }

Comments on this post

peter posts on Aug 31, 2006 at 22:25
BTW, 'ez_where' plugin has some things similar to this. (Not to disparage your technique which is also good :))

I also think Rails is going to (or may already) support syntax like this:

find(:all, :conditions => { :user_id => 3, :job_id => 4 })
moneypenny posts on Sep 01, 2006 at 12:25
I'll look into 'ez_where' and especially that possible Rails syntax, because that would be awesome.
court3nay posts on Oct 11, 2006 at 16:40
find :all, :conditions => ['blah = :blah and foo = :foo', { :blah => 5, :foo => 6 }]
which lets you do

conditions[0] << " and x = :stuff"
conditions[1][:stuff] = "monkeys"
blackrat posts on Dec 16, 2006 at 16:42
Rails 1.2 (RC1) has the syntax suggested by Peter.

You need to create an account or log in to post comments to this site.


Click here to browse all 4863 code snippets

Related Posts