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.