Strange Array behaviour

I’m having a strange thing when using the Enumerable extensions for
Rails:
Have a look at the following code:

class Invoice < ActiveRecord::Base
has_many :invoice_lines

def total
invoice_lines.sum(&:total)
end
end

class InvoiceLine < ActiveRecord::Base
belongs_to :invoice

def total
amount * price
end
end

Now, when calling invoice.total, I get wrong number of arguments (1 for
2) error, but when changing the the total method in Invoice to:

def total
invoice_lines.to_a.sum(&:total)
end

I’m not sure what causes the extra ‘to_a’ to get the thing to work,
since invoice_lines.class also returns Array.

Anyone?

On 29 Nov 2007, at 16:35, Wouter de Bie wrote:

I’m not sure what causes the extra ‘to_a’ to get the thing to work,
since invoice_lines.class also returns Array.

invoice_lines.class returns Array, but invoice_lines is not an Array,
but an association proxy.

This association proxy defines a sum (and count etc…) method that is
analogous to the one available on any model.
So in the same way that you would do Invoice.sum(:column_name), you
need to do invoice_lines.sum(:total)

The reason the to_a makes a difference is that it forces the proxy
class to give you the real array.

Fred

Frederick C. wrote:

On 29 Nov 2007, at 16:35, Wouter de Bie wrote:

I’m not sure what causes the extra ‘to_a’ to get the thing to work,
since invoice_lines.class also returns Array.

invoice_lines.class returns Array, but invoice_lines is not an Array,
but an association proxy.

Aha! I see! What I don’t really understand is that invoice_lines.class
is an Array and not something like an ArrayAssociationProxy (or
something along those lines), since (imho) one of Ruby’s awesome
features is duck typing… In this case, it looks like a duck but doesn’t
quack like one.

Wouter

Another thing I noticed is that sum() on the object requires the name of
a column and not an attribute of the object. I have a case where I want
the sum of a calculated attribute, so I need the to_a in between. I’m
not sure if this is nice behavior.