My app has photos, and users can search for photos that meet certain criteria. Let's say a user searches for photos by tag, and we get something like this:
@results = Photo.tagged_with('mountain')
Now, @results
is going to be a standard activerecord query with multiple records. These would be shown in a grid, and a user can then click on a photo. This would take the users to the photos#show
action.
So, lets say the user searches for something and the app finds 5 records, [1,2,3,4,5]
, and the user clicks on photo #3.
On the photo#show
page I'd like to be able to show a "Next Photo", "Previous Photo", and "Back to Search".
The only other constraint is, if the user browses to a photo directly (via another page or a bookmark etc) there wouldn't be a logical "next" and "previous" photo since there wasn't a query that led them to that photo, so in that case the template shouldn't render the query-related content at all.
So, I have been thinking about how to do this kind of thing and I don't really have a lot of good ideas. I suppose I could do something like store the query in session to be able to go back to it, but I don't know how to find the photos that would have shown up to the left and right of the selected photo.
Does anyone have any examples of how to do this kind of thing?
Andrew, your method not universal and dont give guaranteed right result. There is better way to do this. In your model:
def previous
Photo.where('photos.id < ?', self.id).first
end
def next
Photo.where('photos.id > ?', self.id).last
end
And in views:
- if @photo.previous
= link_to 'Previous', @photo.previous
- if @photo.next
= link_to 'Next', @photo.next
So, after much trial and error, here is what I came up with:
In my Photo model:
# NEXT / PREVIOUS FUNCTIONALITY
def previous(query)
unless query.nil?
index = query.find_index(self.id)
prev_id = query[index-1] unless index.zero?
self.class.find_by_id(prev_id)
end
end
def next(query)
unless query.nil?
index = query.find_index(self.id)
next_id = query[index+1] unless index == query.size
self.class.find_by_id(next_id)
end
end
This method returns the next and previous record from a search or a particular folder view by accepting an array of those records ids. I generate that ID in any controller view that creates a query view (ie the search page and the browse by folders page):
So, for instance, my search controller contains:
def search
@search = @collection.photos.search(params[:search])
@photos = @search.page(params[:page]).per(20)
session[:query] = @photos.map(&:id)
end
And then the photo#show action contains:
if session[:query]
@next_photo = @photo.next(session[:query])
@prev_photo = @photo.previous(session[:query])
end
And lastly, my view contains:
- if @prev_photo || @next_photo
#navigation
.header Related Photos
.prev
= link_to image_tag( @prev_photo.file.url :tenth ), collection_photo_path(@collection, @prev_photo) if @prev_photo
- if @prev_photo
%span Previous
.next
= link_to image_tag( @next_photo.file.url :tenth ), collection_photo_path(@collection, @next_photo) if @next_photo
- if @next_photo
%span Next
Now it turns out this works great in regular browsing situations -- but there is one gotcha that I have not yet fixed:
Theoretically, if a user searches a view, then jumps to a photo they've generated a query in session. If, for some reason, they then browse directly (via URL or bookmark) to another photo that was part of the previous query, the query will persist in session and the related photos links will still be visible on the second photo -- even though they shouldn't be on a photo someone loaded via bookmark.
However, in real life use cases this situation has actually been pretty difficult to recreate, and the code is working very well for the moment. At some point when I come up with a good fix for that one remaining gotcha I'll post it, but for now if anyone uses this idea just be aware that possibility exists.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With