Dynamic Where clause for :conditions in AR::Base.find

where plugin later today unles you would rather do it? Let me know.

Looks good (from skimming over the code). I’m returning from our
mountain retreat to the city today, so I likely won’t have time to
write that patch. Feel free to do it, I’ll integrate it later then.

I have update the plugin to use your class (removing my Where class
in the process, thus breaking old code) and created a descriptive
page for the plugin:

http://blog.invisible.ch/?p=497

cu jc

On Jan 2, 2006, at 1:00 PM, Jens-Christian F. wrote:

http://blog.invisible.ch/?p=497

cu jc

JC-

Cool, looks good! I like that you can still use the sql and  the

between operator as well. I think this will be a pretty useful
plugin. Nice job.

Cheers-
-Ezra Z.
WebMaster
Yakima Herald-Republic Newspaper
[email protected]
509-577-7732

I just found a problem that I’m not sure how to solve:

Converting this:

Task.find(:all, :conditions => [‘project_id = ?’, self.id] )

to

Task.find_with_conditions(:all) do
project_id ‘=’, self.id
end

breaks horrible, because “self.id” in the block references god knows
what (probably the Cond block) instead of the ActiveRecord object. A
work around is to use a temporary variable:

id = self.id
Task.find_with_conditions(:all) do
project_id ‘=’, id
end

Hmm - not that nice. Any ideas on how to solve that?

jc

Jens-Christian-

So I played with things a bit to make the Cond class take a block

and make the find_with_conditions pass the block into the Cond.new
statement. Here is the simplified code that if you made some changes
to your Where class you could use the method_missing interface. Its
using my Cond class instead of your Where class for now and a
simplified version of the find_with_conditions just for examples sake:

class Cond

def initialize(&block)
@args = []
instance_eval(&block) if block_given?
end

def method_missing(sym, *args)
@args << [sym,args.flatten].flatten
end

def where(args=@args)
args.each do |triplet|
instance_variable_set("@#{triplet[0].to_sym}", triplet[2])
end
q = []
ary = []
args.each do |triplet|
iv = instance_variable_get("@#{triplet[0]}")
unless iv.nil? || iv.to_s == ‘’
q << “#{triplet[0]} #{triplet[1]} ?”
ary << iv
end
end
return [q.join(" and ")].concat(ary)
end
end

class Base
def self.find_with_conditions(*args, &block)
cond = Cond.new(&block)
#code goes here for dealing with the options hash merge and
calling find.
# simplified for examples sake we will just return the where
clause for now
cond.where
end
end

a = Base.find_with_conditions do
month ‘<=’, 11
year ‘=’ , “red”
end

p a
#=> [“month <= ? and year = ?”, 11, “red”]

So if you make your Where class use an initialize method that takes

a block like my Cond class above does, then you can use the nice
syntax with either find_with_conditions by passing the block into the
constructor like this: Cond.new(&block) or when you just want to
build the where clause by itself like this:

c = Cond.new do
month ‘<=’, 11
year ‘=’, 2005
name ‘LIKE’, ‘ruby%’
end

c.where

=> [“month <= ? and year = ? and name LIKE ?”, 11, 2005, “ruby%”]

Play with that for a bit and see if you like it. I think it will be

the easiest way to get the syntax we like. I will make this a patch
for your where plugin later today unles you would rather do it? Let
me know.

Cheers-

-Ezra Z.
WebMaster
Yakima Herald-Republic Newspaper
[email protected]
509-577-7732

On Jan 3, 2006, at 1:31 AM, Jens-Christian F. wrote:

end
Hmm - not that nice. Any ideas on how to solve that?

jc

Jens-

I think that I know a way around it. If you wrap it like "#

{self.id}" , I think it will get evaluated before self refers to the
Cond class inside the block. Can you try it and confirm that this works?

Task.find_with_conditions(:all) do
project_id ‘=’, “#{self.id}”
end

Thanks-

-Ezra Z.
Yakima Herald-Republic
WebMaster
http://yakimaherald.com
509-577-7732
[email protected]