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

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 = User.new     user.save     purchase = user.purchases.build

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.

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.

Jeff purpleworkshops.com

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.