Pins on a red mat

‘Fix’ first & last by explicitly setting implicit ordering

Using UUIDs as primary keys has many benefits. However, it causes issues with Rails’s implicit ordering.

In a previous article, I suggested using named scopes alongside first and last, but there is now an easier way to re-enable the default behaviour of Active Record.

Instead of…

…avoiding #first & #last when using non-sequential ids on an Active Record model, or using the extra specificity provided by a named scope…

Use

implicit_order_column within your model and aim it at the automatically generated created_at column.

class Coffee < ApplicationRecord
  self.implicit_order_column = "created_at"
end

Why?

There are major benefits to using UUIDs in your database: uniqueness, assignability, and security.

With this one-line change you also retain the benefits of Rails’ .first and .last helper methods, provided you assign the implicit_order_column to the created_at timestamp.

Why not?

This is a Rails 6 feature. Prior versions of Rails still require the explicit ordering implementation previously explained.

You may still prefer using the explicit ordering approach for greater clarity.

If you do not use UUIDs in your data model, there’s little point in using this.

Note that if two records are created at exactly the same time, the order of the results for those records will be based on the order of their primary key.

Another issue is that, by default, created_at does not have a database index, unlike the id primary key. Running the query without the index could take a while if the dataset is very large. You should add an database index on the created_at field.

Hat tip

My friend Tekin came up with the idea and implemented it in Rails.

Benjamin Alexander for making the point about needing a database index on created_at.


originally posted on 01 Mar 2020 by @andycroll

photo by
Jeff Frenette

Don’t miss my next post, sign up to the One Ruby Thing email and get my next post in your inbox.

Don’t miss my next post, sign up to the One Ruby Thing email and get my next post in your inbox.