I have a Location
model that has_many
LocationPhotos
. The Location
also belongs_to
a single LocationPhoto
as the featured_location_photo
. The belongs_to
association looks like this:
class Location < ActiveRecord::Base
belongs_to :featured_location_photo, class_name: 'LocationPhoto', foreign_key: 'featured_location_photo_id'
end
Using will_paginate, I can paginate the photos for a location like this:
location.location_photos.paginate(page: 1, per_page: 4)
Ideally, I would like to always include the featured_location_photo
as the first element, on the first page, of the collection that's returned, and not be included again. So, for example, if the related photos have ids 1,2,3,4,5,6 and the featured photo has id 3, I would want page one to show photos with ids:
3, 1, 2, 4
And page two to show photos with ids:
5, 6
The collection should also show total_entries
equal to 6.
Is there any way to do this? I can't think of a way to do it by scoping the query because there's no way to tell the featured photo to sort to the top of the results.
My other thought is to first check if the location has a featured photo. If it does, remove that from the query with a scope:
result = location.location_photos.where.not(id: [featured_photo_id]).paginate(page: 1, per_page: 4)
Then, I would need to add the featured photo back into the front of result
.
I'm totally saving this, because I've needed to solve this problem before and always copped out on the solution. Thanks for making me find this!!!
To promote a specific record in a collection use:
order("case when id = #{id} then 0 else id end")
Which means you can just create a custom scope like so:
class Location < ActiveRecord::Base
def photos
location_photos.
order("case when id = #{featured_location_photo_id} then 0 else id end")
end
end
EDIT: actually, ActiveRecord relations respond to unshift
just like arrays. So all you actually need is this:
def photos
location_photos.unshift( featured_location_photo )
end
Which of course you can then paginate.