Modifying Conditions for has_many at runtime in controller?

I am attempting to bring Rails into my company, and so far I have been
able to impress the senior managers with the flexibility /
configurability of Rails on ActiveScaffold. I have hit a point now
where I am stumped, and would really appreciate the help of the
community.

I have a Person ActiveRecord model that has_many Orders.

class Person < ActiveRecord::Base
  has_many :orders
end

I am building out a simple reporting tool. The tool allows the user
to set criteria for which People they want to see. For example, "show
only the People/Orders where the Order's value is greater than $100"

When the user sets this criteria on a web form, I now need to modify
my has_many association. I now need the association to be:

class Person < ActiveRecord::Base
  has_many :orders, :conditions => "ORDER_VALUE > 100"
end

This way, when I do a person.orders.count, I should only get the count
of orders where the Order Value is greater than $100.

Is there any way I can do what I'm describing here? I'm open to any/
all possibilities here.

Thanks for your help! I'm very close to selling my company on using
Rails for some bigger projects!

Robert H. Goretsky
Hoboken, NJ

Just do person.orders.find(:all, :conditions => ['order_value > ?',
100]) and leave the conditions off of your relation declaration.
You may want to wrap that in a method or even look for a slicker way
of doing the same thing as I believe there are more "rails-fu" ways
of doing that sort of find now

-Michael
http://javathehutt.blogspot.com

dear sender,
i�m out of the office until may 29th.
your email will not be forwarded.
for urgent stuff please contact joern@fork.de
kind regards,
alexander

Michael,
Thanks for the response! The issue I have with just using

person.orders.find(:all, :conditions => ['order_value > ?', 100])

is:
a) It does not remove all of the Person records that do not have an
order_value > 100 from the collection of People. So, my report would
end up showing a lot of parent Person records that have no children.

b) It does not update the person.orders count correctly to only count
the children with order_value > 100.

c) (I know this is somewhat outside the scope of this discussion, but
figure I list it to be fair) -- I'm using ActiveScaffold, which just
wraps associated parent/children models into beautiful nested view
code. I'd rather not put tons of ugly customizations in if all I
really need is this one silly condition added to the has_many
association.

Any ideas on how to accomplish what I'm going after here?

Thanks again,
Rob

Robert Goretsky wrote:

Michael,
Thanks for the response! The issue I have with just using

person.orders.find(:all, :conditions => ['order_value > ?', 100])

is:
a) It does not remove all of the Person records that do not have an
order_value > 100 from the collection of People. So, my report would
end up showing a lot of parent Person records that have no children.

b) It does not update the person.orders count correctly to only count
the children with order_value > 100.

http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/5199cea1d6267c5c/06a1f5da4203a11d
http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/7f7f715d917b9faa/426c768dd282929f

Mark,
Thanks, your link to the discussion from last year was exactly what I
needed!

I was looking for a way to dynamically modify has_many conditions, and
the answer you linked to, using the reflect_on_association class
method of ActiveRecord, was the way to go.

Person.reflect_on_association(:conditional_orders).options[:conditions]
= ....(new dynamic conditions)...

Thanks again for your help!

-Rob

Mark,
I was just thinking about this some more and I think I will hit a
severe issue when deploying this application to multiple users using
your suggestion.

I'm assuming that using the reflect_on_association method is giving me
access to a class variable of the Person class that holds the
conditions.

I have read that class variables are SHARED across user instances in a
production Mongrel/Webrick environment. So, if I have > 1 concurrent
web users, when one web user sets a condition, now all web users will
have this condition set!

Am I misunderstanding ActiveRecord's implementation of associations as
class varibles here, or am I correct?

Thanks again..

-Rob

Robert Goretsky wrote:

Mark,
I was just thinking about this some more and I think I will hit a
severe issue when deploying this application to multiple users using
your suggestion.

I'm assuming that using the reflect_on_association method is giving me
access to a class variable of the Person class that holds the
conditions.

I have read that class variables are SHARED across user instances in a
production Mongrel/Webrick environment. So, if I have > 1 concurrent
web users, when one web user sets a condition, now all web users will
have this condition set!

Am I misunderstanding ActiveRecord's implementation of associations as
class varibles here, or am I correct?

Rob, yes, the condition will change for all requests on that Rails
process, but requests are currently handled serially on each of these
processes, so you can set the condition, do the find, then set it back,
perhaps using an automatic wrapper around the finds through a custom
find method, or by putting finds in a block that is yielded-to by a
condition-setting method. If and when Rails becomes multi-threaded,
some locks can be added to the condition-setting method.

And you only need to reset the condition if the find sometimes needs
to be done without condition. If that's the case, an alternative to
condition reset would be to define the association twice, one fixed
and condition-less, and one with a name suffix that indicates use of
a dynamic condition.