Find based on conditions defined in the model

Hi all,

Does anyone know how to run a find where a condition is based on an
attribute specified in an object’s model? I have a Payment object,
and in its model I have a function called “amount_unapplied”. That
code is:

Return the amount of the payment that has been applied to invoices

def amount_applied
return self.splits.sum(:amount) == nil ? 0 :
self.splits.sum(:amount)
end

In one of my controller methods, I have to return all of the Payment
records where amount_unapplied > 0. If I specify it as one of
the :conditions in a find, such as:

pmts = Payment.find(:all, :conditions => amount_unapplied > 0)

I get an “undefined local variable or method `amount_unapplied’”
exception, as there is no actual column called amount_unapplied…

Any ideas? Thanks!

Neal L wrote:

Hi all,

Does anyone know how to run a find where a condition is based on an
attribute specified in an object’s model? I have a Payment object,
and in its model I have a function called “amount_unapplied”. That
code is:

Return the amount of the payment that has been applied to invoices

def amount_applied
return self.splits.sum(:amount) == nil ? 0 :
self.splits.sum(:amount)
end

In one of my controller methods, I have to return all of the Payment
records where amount_unapplied > 0. If I specify it as one of
the :conditions in a find, such as:

pmts = Payment.find(:all, :conditions => amount_unapplied > 0)

I get an “undefined local variable or method `amount_unapplied’”
exception, as there is no actual column called amount_unapplied…

Any ideas? Thanks!

You could create a custom method in your model…

def self.unapplied_payments
find(:all).map {|p| [p] if p.amount_unapplied > 0}.delete_if {|x|
x.nil?}
end

This line finds all payments, uses array.map to step through and keep
the ones that meet the condition amount_unapplied > 0, and deletes out
the leftover nil values (the ones where amount_unapplied <= 0).

Payment.unapplied_payments now returns a collection of payments where
amount_unapplied > 0

This is a starting point. As you can see it makes a full-table select
first and then steps through them - not very efficient. You’d definitely
want to enhance your custom method to take normal :find options and
apply them before the mapping to improve performance.

Option 2 would be to have an “amount_applied” field on your payment
table which you keep up-to-date, then do a normal find with :conditions
on that field. It’s a tradeoff, but here you get to use the power of the
database for the filtering.

Cayce,
That was a beautiful explanation…I think you have much ‘teacher’ in
you.
Where did you find out about the ‘delete_if’ method? I’ve never seen
it before.
Kathleen
[email protected]

On Jun 4, 10:22 pm, Cayce B. [email protected]

[email protected] wrote:

Cayce,
That was a beautiful explanation…I think you have much ‘teacher’ in
you.
Where did you find out about the ‘delete_if’ method? I’ve never seen
it before.
Kathleen
[email protected]

On Jun 4, 10:22�pm, Cayce B. [email protected]

“delete_if” is a standard method on the Ruby Array class - don’t forget
it’s all Ruby underneath! :slight_smile:

RDoc Documentation for documentation of Ruby classes. Click
on “Array” or “String” or “Integer” under Classes and you’ll see
documentation of all the standard methods.

Glad I could help and I appreciate the kind words.