Making first/last deterministic when using UUID primary keys

Hiya,

I’m working on a project that uses PostgreSQL UUIDs as primary keys. I’d like to make the first and last finder methods behave more predictably without having to resort to explicit order calls everywhere or setting default scopes. Having looked through the code for the finder methods, one option that has presented itself is to make the default sort order configurable so a column other than primary_key can be specified. I’m up for working on a patch for this but thought I’d post here for thoughts before I got stuck in. I’m imagining something like this to specify it:

class Model < ApplicationRecord
default_order_column :created_at
end

Any thoughts?

Thanks in advance,

Tekin

Why not simply use default scope with ordering? I believe it would be equivalent.

I.e.:

default_scope { order(created_at: :desc) }

+1 for main thread. (I’d faced kinda same problem in one of my previous projects.)

And using default_scope. I think using default_scope might mess with the situation when default_scope is already being used for some other purpose (other than default_scope is already referred as a bit dangerous play in long run).

Also it’s to have an exact functionality, then a work-around using some function intended for different purposes.

There would be a difference in behaviour because default scopes are greedy and need explicit unscoping to override. This can result in unexpected/surprising behaviour. To illustrate this using the default scope described above, calling

Model.order(:name).first

Would result in the following order clause:

…ORDER BY created_at DESC, name ASC…

i.e. the default scope ordering is always included and any additional order clauses are appended. You’d have to remember to call reorder() or unscoped() instead.

A configurable default order column would differ in that it would be a fallback if no explicit order is specified, i.e. the order clause would look like:

…ORDER BY name ASC…

Tekin

Why not to use simple scope?

class SomeActiverecordClass
  scope :ordered, -> {order(created_at: :desc)}
end

This is what we do currently.

The problem isn’t that it’s impossible to scope a relation so that first/last return the first/last created records. It’s that there is an inconsistency in behaviour when using non-incremental primary keys, which can lead to confusion and catch people out.

Unfortunately calling first/last without an ordered scope has become part of the muscle memory of the Rails community precisely because the methods default to ordering by primary key, which has acted as a proxy for creation order. This change would make it possible to configure models with uuids as their primary key so that first/last return something closer to what people expect.

Tekin

If I use first/last in my code, I tend to also use an ‘ordered’ scope as my criteria for order varies from case to case, although I generally use created_at as that criteria. I prefer my code to be more explicit about it’s ordering when I’m looking at it anyway.

Hiya,

Does anyone have any thoughts as to whether this change is likely to be accepted? I’m more than happy to work up a PR.

Rails already has default_scope for situations like this

class Model < ApplicationRecord
  default_scope { order("created_at) }
end

Would this be sufficient?

Rails already has default_scope for situations like this

class Model < ApplicationRecord
default_scope { order("created_at) }
end

Would this be sufficient?

Covered this in a previous response. See below.