This does sound like a bug to me.
When I was originally designing the Collection API a couple of years
ago, it was really hard to reason about how things should work until I
started to imagine what would happen in Ruby if I had loaded up the
entire set of resources into an Array and was filtering through that
using Array/Enumerable methods.
So for example, it's a bug if these two statements do not return the
same records:
Task.all(:limit => 10).last
Task.to_a[0, 10].last
One confusing point, that I didn't realize until after everything was
done and we started using the API, was that the Hash based interface
doesn't make it completely clear the operator precedence, eg.
{ :limit => 10, :subscriber => true }
Some people might think this means "limit the results to 10, then
filter subscriber records" OR "filter subscriber records, then limit
those results to 10". I think most people identify with the second
approach, which is similar to what we've had ingrained from SQL usage
(in a SELECT the WHERE clause applies first, then the LIMIT). However,
the first isn't technically wrong.. it's the API which is ambiguous. I
didn't see this ambiguity because I've always identified with the SQL
approach and didn't question it when designing the API.
(I'm looking at ways to reduce this ambiguity in future API revisions,
but I don't have anything concrete yet to demo.)
The following statement should order the tasks by "ordering", then
limit the results to 10, then return the last task from that list:
Task.all(:limit => 10, :order => [ :ordering.asc ]).last
The Hash based interface is a bit unclear, and it could be causing the
bug in how Collection#last should behave. The Collection#first and
Collection#last methods should always evaluate the same as if they
were being called on a collection that was materialized into an Array,
as in Array#first and Array#last.
In fact this might be OT, but not alot of people know this;
Collection#first and Collection#last, like their Array counterparts,
also accept an integer which will allow the first/last n resources to
be returned, eg:
players = Player.all(:order => [ :points ])
players.first(5) # top 5 players
players.last(5) # bottom 5 players
Anyway, to summarize: When in doubt, look at how Array/Enumerable
methods behave and that is how Collection should behave, if possible.
--
Dan