-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
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 BYis not explicitly dictating order. created_atand 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) }