image by Austris Augusts
Active Record’s first and last may not mean what you think
Each Active Record model comes with the well-used ‘get me a single record’ scopes: .first
and .last
.
Instead of…
…using the methods directly on the base ActiveRecord class.
User.first
User.last
Use…
…them only with ordered scopes. Ideally with named concepts.
app/models/user.rb
class User < ActiveRecord::Base
scope :by_created, -> { order(created_at: :asc) }
scope :earliest_created, -> { by_created.first }
scope :most_recently_created, -> { by_created.last }
# …
end
User.most_recently_created
But why?
This is mostly about making the code more explicit.
The .first
and .last
methods, when called on a bare Active Record model scope, mean the ‘lowest id
’ and the ‘highest id
’. However we colloquially use them to mean ‘created first’ and ‘created most recently’.
This is an accident of the default database configuration of Rails.
Objects in the database are created, by default, with an incrementing integer id
. This means that ordering by this ascending id
is the same as if we ordered by the created_at
timestamp.
But using these scopes with no explicit order means you are ordering by ‘id
assigned by the database’, not by recency.
If you took my advice from a previous article about using UUIDs for primary keys the result of calling .first
and .last
might surprise you.
The default ordering is still on an Active Record object’s id
which is now random. So when you create a User
it is not automatically available as User.last
.
Why not?
Implementing this leads to more code and Rails’ conventions on this are long-standing. You might not feel this is worth it.
You’ll probably also need to add an index to created_at
so you can keep your new scopes snappy.
Last updated on May 27th, 2018