How can I define custom getter functions for ActiveRecord objects in Ruby that will perform operations on an array of the ActiveRecord objects?
For example, I would like to return weighted averages on an array of objects. So if I have Loan objects (1,2,3) with fields amount (100, 200, 300) and default_rate (.1, .2, .3), then with the normal ActiveRecord functions Loan.find(1).amount should return 100, Loan.find(2).default_rate should return .2.
But if I had Loan.find(2,3).default_rate, I would like it to return the weighted average of the default rates, which is .26. I know I can do this using SQL select statements but how can I “overload” the ActiveRecord getter to allow be to define a function when I call the getter on an array of Loan objects rather than a single Loan object?
The loan table has fields amount id, amount, and default_rate
class Loan < ActiveRecord::Base
module Collection
def default_rate
sum(:default_rate * :amount) / sum(:amount)
end
end
end
class LoanGroup
has_many :loans, :extend => Loan::Collection
end
#Then I try
obj = LoanGroup.where('id < 10')
This gives me the error that has_many is undefined in LoanGroup
To avoid polluting
Array‘s namespace with methods specific to collections ofLoanrecords, you might make a wrapper for such a collection and call your methods on that.Something like:
Original answer below: using an association extension
Use an association extension. This way the method will be the same whether on a loan, or a collection of loans.
If you wanted to keep the logic for loans in the
Loanclass, you could also write the extension there, e.g.:Edit: as @Santosh points out
association.finddoes not return a relation, so it will not work here. You’d have to usewhereor some other method which returns a relation.