FIX: Ensure directory items appear in a consistent order (#11370)

User directory items are sorted by some activity metric. If those metrics have the same value, postgres does not guarantee the order in which they will be returned. This can cause issues in pagination - some users may appear twice, and some may be missed. To illustrate

```
pry(main)> query = DirectoryItem.where(period_type: DirectoryItem.period_types[:weekly]).order(:likes_received).limit(50);
pry(main)> page1 = query.offset(0).pluck(:id);
pry(main)> page2 = query.offset(50).pluck(:id);
pry(main)> (page1 & page2).count # users on both pages
=> 29
```

If we use the primary key to tie-break matching metrics, things are much more reliable

```
pry(main)> query = DirectoryItem.where(period_type: DirectoryItem.period_types[:weekly]).order(:likes_received, :id).limit(50);
pry(main)> page1 = query.offset(0).pluck(:id);
pry(main)> page2 = query.offset(50).pluck(:id);
pry(main)> (page1 & page2).count # users on both pages
=> 0
```

This most commonly effects new sites where all the directory metrics are zero.

The fact that the ordering is indeterminate makes it difficult to write a reliable test case for this.
This commit is contained in:
David Taylor 2020-11-27 18:12:49 +00:00 committed by GitHub
parent 65eec147fc
commit e7bad9f05d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -29,9 +29,9 @@ class DirectoryItemsController < ApplicationController
order = params[:order] || DirectoryItem.headings.first
dir = params[:asc] ? 'ASC' : 'DESC'
if DirectoryItem.headings.include?(order.to_sym)
result = result.order("directory_items.#{order} #{dir}")
result = result.order("directory_items.#{order} #{dir}, directory_items.id")
elsif params[:order] === 'username'
result = result.order("users.#{order} #{dir}")
result = result.order("users.#{order} #{dir}, directory_items.id")
end
if period_type == DirectoryItem.period_types[:all]