CSN
2005-Nov-22 02:57 UTC
Building a conditions clause (for find) of multiple optional params?
I want to be able to find items according to various params - category_id, member_id, type_id, rating, etc. What I have now is something like: if(@params[''category_id'']) @items=Item.find(:all, :conditions=>["category_id=?", @params[''category_id'']) elsif(@params[''category_id''] and @params[''member_id'']) @items=Item.find(:all, :conditions=>["category_id=? and member_id=?", @params[''category_id''], @params[''member_id'']) elsif ... end Is there a simpler way? Such as just adding to a conditions array, then joining and passing it to find() as :conditions? thanks csn __________________________________ Yahoo! FareChase: Search multiple travel sites in one click. http://farechase.yahoo.com
Christer Nilsson
2005-Nov-22 06:58 UTC
Re: Building a conditions clause (for find) of multiple opti
I have looked for a solution, but without success. Your solution
explodes as 2^5=32 possibilities.
This is my suggestion. I need some advice regarding quotes and sql
injection.
class Array
def AddCond(query, value)
return if value.blank?
self << "#{query} #{Report.quote(value)}"
end
def AddLike(query, prefix, value, suffix)
return if value.blank?
self << "#{query} LIKE #{Report.quote(prefix+value+suffix)}"
end
end
cond = ["1=1"]
cond.AddCond("category_id =",
@params[''category_id''))
cond.AddCond("member_id =", @params[''member_id''))
...
cond.AddLike("member_name", "%",
@params[''member_name''], "%")
... :conditions => cond.join(" and ") ...
--
Posted via http://www.ruby-forum.com/.
CSN
2005-Nov-22 08:55 UTC
Re: Re: Building a conditions clause (for find) of multiple opti
I came up with: conditions=["var1=1"] if(@params[''member_id'']) conditions[0] += " and member_id=?" conditions.push(@params[''member_id'']) end if(@params[''category_id'']) conditions[0] += " and category_id=?" conditions.push(@params[''category_id'']) end @items=Items.find(:all, :conditions=>conditions) It obviously needs a better way of handling the first array element and/or figuring out whether a condition is the first and whether to add " and ". csn --- Christer Nilsson <janchrister.nilsson-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> I have looked for a solution, but without success. Your solution > explodes as 2^5=32 possibilities. > > This is my suggestion. I need some advice regarding quotes and sql > injection. > > class Array > def AddCond(query, value) > return if value.blank? > self << "#{query} #{Report.quote(value)}" > end > def AddLike(query, prefix, value, suffix) > return if value.blank? > self << "#{query} LIKE #{Report.quote(prefix+value+suffix)}" > end > end > > cond = ["1=1"] > cond.AddCond("category_id =", @params[''category_id'')) > cond.AddCond("member_id =", @params[''member_id'')) > ... > cond.AddLike("member_name", "%", @params[''member_name''], "%") > > ... :conditions => cond.join(" and ") ... > > > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >__________________________________ Yahoo! Mail - PC Magazine Editors'' Choice 2005 http://mail.yahoo.com
Peter Bohm
2005-Nov-22 10:21 UTC
Re: Building a conditions clause (for find) of multiple opti
Just initialize conditions[0] with some always true statements something like... conditions[0] = " true " or conditions[0] = "1 = 1" It''s also possible to use named parameters, which may be a bit more readable - you will have one String with sql and one Hash with named parameters Peter CSN wrote:> I came up with: > > conditions=["var1=1"] > if(@params[''member_id'']) > conditions[0] += " and member_id=?" > conditions.push(@params[''member_id'']) > end > if(@params[''category_id'']) > conditions[0] += " and category_id=?" > conditions.push(@params[''category_id'']) > end > > @items=Items.find(:all, :conditions=>conditions) > > It obviously needs a better way of handling the first array element and/or figuring out whether a > condition is the first and whether to add " and ". > > csn > > > --- Christer Nilsson <janchrister.nilsson-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > >>I have looked for a solution, but without success. Your solution >>explodes as 2^5=32 possibilities. >> >>This is my suggestion. I need some advice regarding quotes and sql >>injection. >> >>class Array >> def AddCond(query, value) >> return if value.blank? >> self << "#{query} #{Report.quote(value)}" >> end >> def AddLike(query, prefix, value, suffix) >> return if value.blank? >> self << "#{query} LIKE #{Report.quote(prefix+value+suffix)}" >> end >>end >> >>cond = ["1=1"] >>cond.AddCond("category_id =", @params[''category_id'')) >>cond.AddCond("member_id =", @params[''member_id'')) >>... >>cond.AddLike("member_name", "%", @params[''member_name''], "%") >> >>... :conditions => cond.join(" and ") ... >> >> >>-- >>Posted via http://www.ruby-forum.com/. >>_______________________________________________ >>Rails mailing list >>Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org >>http://lists.rubyonrails.org/mailman/listinfo/rails >> > > > > > > > __________________________________ > Yahoo! Mail - PC Magazine Editors'' Choice 2005 > http://mail.yahoo.com
CSN
2005-Nov-22 11:21 UTC
Re: Re: Building a conditions clause (for find) of multiple opti
--- Peter Bohm <Bohm-Uls/rNv2J19iPCr66r4cLw@public.gmane.org> wrote:> Just initialize conditions[0] with some always true statements something > like... > conditions[0] = " true " or conditions[0] = "1 = 1" > > It''s also possible to use named parameters, which may be a bit more > readable - you will have one String with sql and one Hash with named > parametersI''m not sure I understand what it''d look like - could you give a code example? thanks csn> > Peter > > CSN wrote: > > I came up with: > > > > conditions=["var1=1"] > > if(@params[''member_id'']) > > conditions[0] += " and member_id=?" > > conditions.push(@params[''member_id'']) > > end > > if(@params[''category_id'']) > > conditions[0] += " and category_id=?" > > conditions.push(@params[''category_id'']) > > end > > > > @items=Items.find(:all, :conditions=>conditions) > > > > It obviously needs a better way of handling the first array element and/or figuring out > whether a > > condition is the first and whether to add " and ". > > > > csn > > > > > > --- Christer Nilsson <janchrister.nilsson-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > > > >>I have looked for a solution, but without success. Your solution > >>explodes as 2^5=32 possibilities. > >> > >>This is my suggestion. I need some advice regarding quotes and sql > >>injection. > >> > >>class Array > >> def AddCond(query, value) > >> return if value.blank? > >> self << "#{query} #{Report.quote(value)}" > >> end > >> def AddLike(query, prefix, value, suffix) > >> return if value.blank? > >> self << "#{query} LIKE #{Report.quote(prefix+value+suffix)}" > >> end > >>end > >> > >>cond = ["1=1"] > >>cond.AddCond("category_id =", @params[''category_id'')) > >>cond.AddCond("member_id =", @params[''member_id'')) > >>... > >>cond.AddLike("member_name", "%", @params[''member_name''], "%") > >> > >>... :conditions => cond.join(" and ") ... > >> > >> > >>-- > >>Posted via http://www.ruby-forum.com/. > >>_______________________________________________ > >>Rails mailing list > >>Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > >>http://lists.rubyonrails.org/mailman/listinfo/rails > >> > > > > > > > > > > > > > > __________________________________ > > Yahoo! Mail - PC Magazine Editors'' Choice 2005 > > http://mail.yahoo.com > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >__________________________________ Yahoo! Mail - PC Magazine Editors'' Choice 2005 http://mail.yahoo.com
Lugovoi Nikolai
2005-Nov-22 12:28 UTC
Re: Building a conditions clause (for find) of multiple opti
Well, here''s my suggestion:
class ArFilter
def initialize(default_cond="1=0", operation =
''AND'')
@conds = []
@values = []
@default_cond = default_cond
@operation = operation
end
def add(cond, *values)
@conds << cond
@values += values
end
def conditions
@conds.empty? ? @default_cond : [@conds.join("
"+@operation+" ")] + @values
end
end
in controller:
def sets
filter = ArFilter.new("1=1", "OR")
filter.add("bs_title like ''%'' || ? ||
''%''", params[:qt]) unless params[:qt].blank?
filter.add("bs_year = ?", params[:qy]) unless params[:qy].blank?
@programs = BookSet.find(:all, :order => ''bs_year,
bs_title'', :conditions => filter.conditions)
end
Peter Bohm
2005-Nov-22 12:52 UTC
Re: Building a conditions clause (for find) of multiple opti
I usually use a separate "criteria" class to hold all the search
conditions
class ContactFilter
@name
@phone
attr_writer :name, :phone
attr_reader :name, :phone
end
the filter method would look something like this
def Contact.filter(filter)
sql = "1 = 1 "
conditions = Hash.new
joins = ""
if filter.name != nil
sql += " and name = :name"
conditions[:name] = filter.name
end
if filter.phone != nil
sql += " and (addresses.phone like :phone or
addresses.phone2 like :phone or addresses.fax like :phone)"
conditions[:phone] = "%#{filter.phone}%"
joins += " left join addresses on contacts.id
addresses.contact_id "
end
return Contact.find(:all,
:conditions
=> [sql, conditions],
:joins =>
joins,
:order =>
"name")
end
off course the hash can be appended different way...
Peter
CSN wrote:
--- Peter Bohm wrote:
Just initialize conditions[0] with some always true statements something
like...
conditions[0] = " true " or conditions[0] = "1 = 1"
It''s also possible to use named parameters, which may be a bit more
readable - you will have one String with sql and one Hash with named
parameters
I''m not sure I understand what it''d look like - could you give
a code example?
thanks
csn
Peter
CSN wrote:
I came up with:
conditions=["var1=1"]
if(@params[''member_id''])
conditions[0] += " and member_id=?"
conditions.push(@params[''member_id''])
end
if(@params[''category_id''])
conditions[0] += " and category_id=?"
conditions.push(@params[''category_id''])
end
@items=Items.find(:all, :conditions=>conditions)
It obviously needs a better way of handling the first array element and/or
figuring out
whether a
condition is the first and whether to add " and ".
csn
--- Christer Nilsson wrote:
I have looked for a solution, but without success. Your solution
explodes as 2^5=32 possibilities.
This is my suggestion. I need some advice regarding quotes and sql
injection.
class Array
def AddCond(query, value)
return if value.blank?
self << "#{query} #{Report.quote(value)}"
end
def AddLike(query, prefix, value, suffix)
return if value.blank?
self << "#{query} LIKE
#{Report.quote(prefix+value+suffix)}"
end
end
cond = ["1=1"]
cond.AddCond("category_id =",
@params[''category_id''))
cond.AddCond("member_id =", @params[''member_id''))
...
cond.AddLike("member_name", "%",
@params[''member_name''], "%")
... :conditions => cond.join(" and ") ...
--
Posted via http://www.ruby-forum.com/.
_______________________________________________
Rails mailing list
Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org
http://lists.rubyonrails.org/mailman/listinfo/rails
__________________________________
Yahoo! Mail - PC Magazine Editors'' Choice 2005
http://mail.yahoo.com
_______________________________________________
Rails mailing list
Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org
http://lists.rubyonrails.org/mailman/listinfo/rails
__________________________________
Yahoo! Mail - PC Magazine Editors'' Choice 2005
http://mail.yahoo.com
_______________________________________________
Rails mailing list
Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org
http://lists.rubyonrails.org/mailman/listinfo/rails
Francois Beausoleil
2005-Nov-22 13:52 UTC
Re: Building a conditions clause (for find) of multiple optional params?
Hi ! 2005/11/21, CSN <cool_screen_name90001@yahoo.com>:> I want to be able to find items according to various params - category_id, member_id, type_id, > rating, etc. What I have now is something like:Take a look at "Building the SQL WHERE clause dynamically in Rails" over at http://blog.teksol.info/articles/2005/10/31/building-the-sql-where-clause-dynamically-in-rails Hope that helps ! -- François Beausoleil http://blog.teksol.info/ _______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
Leon Leslie
2005-Nov-22 14:06 UTC
Re: Building a conditions clause (for find) of multiple optional params?
Also have a look at the Query by example mixin by Duane Johnson on the list. On 11/22/05, Francois Beausoleil <francois.beausoleil-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > Hi ! > > 2005/11/21, CSN <cool_screen_name90001-/E1597aS9LQAvxtiuMwx3w@public.gmane.org>: > > I want to be able to find items according to various params - > category_id, member_id, type_id, > > rating, etc. What I have now is something like: > > Take a look at "Building the SQL WHERE clause dynamically in Rails" > over at > http://blog.teksol.info/articles/2005/10/31/building-the-sql-where-clause-dynamically-in-rails > > Hope that helps ! > -- > François Beausoleil > http://blog.teksol.info/ > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails > > >-- First they laugh at you, then they ignore you, then they fight you. Then you win. -- Mahatma Karamchand Gandhi _______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
Christer Nilsson
2005-Nov-22 15:07 UTC
Re: Building a conditions clause (for find) of multiple opti
Francois! That really looks nice! Never mind about 1=1. That will be executed in less than a microsec anyway! If ActiveRecord realized :cond was empty it should suppress "WHERE". Christer -- Posted via http://www.ruby-forum.com/.
Christer Nilsson
2005-Nov-22 15:14 UTC
Re: Building a conditions clause (for find) of multiple opti
Leon! Please give a link to Query by example mixin by Duane Johnson Christer -- Posted via http://www.ruby-forum.com/.
Ezra Zygmuntowicz
2005-Nov-23 06:01 UTC
Re: Re: Building a conditions clause (for find) of multiple opti
Here is another take on building the where clause and builds the
necessary format including the ? placeholders:
class Where
def initialize(p,m,u)
@project = p
@month = m
@user = u
end
def build_where_clause
query = []
ary = []
[:project, :month, :user].each do |i|
iv = instance_variable_get("@#{i}")
unless iv.zero?
query << "#{i} = ?"
ary << iv
end
end
return [q.join(" and ")].concat(ary)
end
end
a = Where.new(1,2,3)
b = Where.new(0,1,2)
c = Where.new(1,0,2)
d = Where.new(0,0,1)
p a.build_where_clause
p b.build_where_clause
p c.build_where_clause
p d.build_where_clause
# results
["project = ? and month = ? and user = ?", 1, 2, 3]
["month = ? and user = ?", 1, 2]
["project = ? and user = ?", 1, 2]
["user = ?", 1]
Cheers-
-Ezra Zygmuntowicz
WebMaster
Yakima Herald-Republic Newspaper
ezra-gdxLOakOTQ9oetBuM9ipNAC/G2K4zDHf@public.gmane.org
509-577-7732