Reputation: 43402
I have an application with many Galleries. Each gallery has a start_date DateTime field.
For legacy reasons, the time of all start_dates is midnight.
Thu, 10 Jul 2014 00:00:00 UTC +00:00
I need to order the galleries by date, so a user can shuffle back and forth across them using a 'older' and 'newer' link. Galleries are ordered based on start_date:
scope :start_date_ascending, -> { order(start_date: :asc) }
scope :start_date_descending, -> { order(start_date: :desc) }
My problem is that there is no clear older or newer gallery when there are multiple galleries with the same date. In such cases I cannot predict the order that Galleries with the same date are returned in, so moving across multiple galleries with the same date becomes random and error-prone.
I have scope set up to find newer and older galleries:
scope :newer_than, -> (gallery){ where.not(id:gallery).where('start_date >= :gallery_start_date', gallery_start_date:gallery.start_date) }
scope :older_than, -> (gallery){ where.not(id:gallery).where('start_date < :gallery_start_date', gallery_start_date:gallery.start_date) }
And I find the next and previous galleries like this:
def self.next_newer(gallery)
Gallery.newer_than(gallery).start_date_ascending.limit(1).first
end
def self.next_older(gallery)
Gallery.older_than(gallery).start_date_descending.limit(1).first
end
So it seems to me I need a secondary way to order the galleries that are the same date. It doesn't matter what order that is - it could simply be their ids.
How can I handle this situation so that galleries with the same date appear in the query in a predictable, fixed order so that next_newer
and next_older
move through them?
Upvotes: 1
Views: 74
Reputation: 13181
Perhaps you can sort with a second criteria, name
for example and if available, or even id
scope :start_date_ascending, -> { order(start_date: :asc, name: :asc) }
scope :start_date_descending, -> { order(start_date: :desc, name: :asc) }
note on the start_date_descending
scope it can be nice to keep name asc
, so despite of the descending date order we keep a alphabetical order
And for the next and previous gallery, if you can store an array, you can get your ordered ids and iterate through them
ids = Gallery.start_date_ascending.pluck :id
Upvotes: 1
Reputation: 43402
Based on @BengaminSinclaire's suggestion:
def self.next_newer(gallery)
ascending_ids = Gallery.start_date_ascending.pluck :id
current_index = ascending_ids.index(gallery.id)
Gallery.find(ascending_ids[current_index+1]) if current_index < ascending_ids.length - 1
end
def self.next_older(gallery)
ascending_ids = Gallery.start_date_ascending.pluck :id
current_index = ascending_ids.index(gallery.id)
Gallery.find(ascending_ids[current_index-1]) if current_index > 0
end
Upvotes: 1