Collection.last does not seem to jive with collection.count after

I was just trying to write a “smart” copy method in a class* and
noticed that the last and count collection methods don’t work the same
after build and before save. In other words, if in my code I do this:

user =
purchase =

Then I get the following:
user.purchases.count => 0
user.purchases.last => #Purchase:0x01234567

It’s never bothered me before now. As a human, I can ask the question
how can the count be 0 if the collection has a last element? I would
expect the last method to return nil in this case because I haven’t
saved purchase yet.

I’m assuming the solution is to create my own “last” method, one that
filters out records with a nil value for created_at. Or another build
method that calls last before build. But both solutions seem un-DRY,
or worse un-DRRoR. But I thought maybe I am missing something.

*In case you’re wondering, the method I’m writing copies certain
values of the last “purchase” model created by that user into a new
one, as a way of setting some default values. Maybe there is a more
rails-ee way of doing that too.

Thanks in advance.

On May 27, 11:47 am, Dee [email protected] wrote:

user.purchases.last => #<Purchase:0x01234567>

That’s because .count is using SQL to look at the table, but you
haven’t committed the new purchase to the db yet. .last knows to use
the in-memory collection instead.

Instead of .count, use .size, which is aware of in-memory changes.

That said, consider using .clone, which will copy an object for you
that you can start with.


Thanks, Jeff.

Thanks for the clarification of the difference between .size
and .count. I was actually looking more for something that does .last
like .count, rather than .count like .last. I got around that by doing
and :order_by => ‘created_at’ before using .last, which puts the nils
at the head, at least in MySQL and SQLite.

Big thanks for clone. It’s brilliant. I didn’t know it existed. It was
beginning to look like a maintenance nightmare without it.