Skip to content

The current order by id recommendation may be subtly introducing bugs. #274

@kitsunde

Description

@kitsunde

I would like to suggest removing https://rails.rubystyle.guide/#order-by-id as a recommendation, or at least rewording it under a chronological ordering headline and changing the recommendation so it's not causing unstable sorting issues.

The background is:

  • id (assumed to be an auto-incrementing sequence) will grant each row 1 unique id.
  • Databases don't guarantee order when ORDER BY is not explicitly dictating order.
  • created_at and such timestamp fields are not (commonly) unique fields.

This means that:

id,created_at
1,2020-01-01
2,2020-01-01

With ORDER BY created_at will get returned both as 1,2 and as 2,1 and this is the expected behaviour. These issues are quite common to find when doing pagination and finding the same record across multiple pages, but even repeatedly asking for the same records will cause records to swap places.

I think this style guide is mixing up presentation layer concerns like showing an order that makes sense to an end-user on a specific column (in this case created time, but it could be a title, updated time or any other non-unique column) - which is situational - with general application-level concerns.

If I wanted to really nitpick the recommendation then timestamps like created_at are not really more reliable than the sequence itself in terms of the chronological order of records since they are in rails commonly set by application servers where clocks have drifted, db calls arrive and execute at different speeds and native SQL like NOW() is frozen to the first invocation inside of a transaction across the duration of the active transaction (in pg anyways) which can take an arbitrarily long time. If anything the sequence is probably closer to the actual chronological order of the record being inserted.

If it's important to keep this recommendation then the id should probably be kept in the order call so queries remain deterministic I.e:

# bad
scope :chronological, -> { order(id: :asc) }

# good
scope :chronological, -> { order(created_at: :asc, id: :asc) }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions