Rails:上一个查询的上一个和下一个记录
我的应用有照片,用户可以搜索符合特定条件的照片。我们先来说说照片用户搜索的标签,而我们得到的东西是这样的:Rails:上一个查询的上一个和下一个记录
@results = Photo.tagged_with('mountain')
现在,@results
将是一个标准的ActiveRecord查询与多个记录。这些将显示在网格中,然后用户可以点击照片。这将使用户执行photos#show
操作。
因此,可以说用户搜索某物,应用程序找到5条记录,[1,2,3,4,5]
,用户点击照片#3。
在photo#show
页面上,我希望能够显示“下一张照片”,“上一张照片”和“返回搜索”。
唯一的另一个限制是,如果用户直接浏览照片(通过另一个页面或书签等),则不会有逻辑的“下一张”和“上一张”照片,因为没有查询将他们引导至该照片,因此在这种情况下,该模板根本不应呈现与查询相关的内容。
所以,我一直在想如何做这种事情,我真的没有太多好主意。我想我可以做一些事情,比如在会话中存储查询,以便能够回到它,但我不知道如何找到显示在所选照片的左侧和右侧的照片。
有没有人有任何如何做这种事情的例子?
所以,大量的试验和错误之后,这里是我想出了:
在我的照片模式:
# 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
这个方法从搜索或特定返回下一个和以前的记录通过接受这些记录ID的数组来查看文件夹视图。我生成,创建一个查询视图的任何控制器认为ID(即搜索页面和文件夹页面浏览):
所以,举例来说,我的搜索控制器包含:
def search
@search = @collection.photos.search(params[:search])
@photos = @search.page(params[:page]).per(20)
session[:query] = @photos.map(&:id)
end
然后是照片显示#操作包含:
if session[:query]
@next_photo = @photo.next(session[:query])
@prev_photo = @photo.previous(session[:query])
end
最后,我认为包含:
- 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
现在,事实证明这个作品中经常浏览的情况不错 - 但有一个疑难杂症,我还没有固定的:
从理论上讲,如果用户搜索一个视图,然后跳转到他们所产生的照片会话中的查询。如果出于某种原因,他们然后直接浏览(通过URL或书签)到另一张属于先前查询的照片,查询将会保留在会话中,并且相关照片链接仍将在第二张照片上可见 - 即使他们不应该在通过书签加载的照片上。
但是,在现实生活中,这种情况实际上很难重新创建,而且代码目前运行良好。在某个时候,当我为剩下的那个问题想出一个很好的解决方案时,我会发布它,但是现在如果有人使用这个想法,请注意可能存在。
你可以看看在ActsAsAdjacent做什么:
named_scope :previous, lambda { |i| {:conditions => ["#{self.table_name}.id < ?", i.id], :order => "#{self.table_name}.id DESC"} }
named_scope :next, lambda { |i| {:conditions => ["#{self.table_name}.id > ?", i.id], :order => "#{self.table_name}.id ASC"} }
从本质上讲,他们的作用域(预Rails 3的语法)来检索具有较小的ID记录/大于记录的ID你传入。
由于它们是作用域,因此可以用.first链接前一个以获取在当前项目之前创建的第一个项目和.tagged_with('mountain')。首先获取第一个标记为'山'。
安德鲁,你的方法不通用,不保证正确的结果。有更好的方法来做到这一点。 在你的模型:
def previous
Photo.where('photos.id < ?', self.id).first
end
def next
Photo.where('photos.id > ?', self.id).last
end
而且在访问量:
- if @photo.previous
= link_to 'Previous', @photo.previous
- if @photo.next
= link_to 'Next', @photo.next
一个我编写的名为Nexter宝石会为你。
您传递一个AR Scope组合(即ActiveRelation)加上当前对象/记录,Nexter将检查order子句以构建将获取before/previous和/ after记录的sql。
基本上它着眼于ActiveRelation#order_values为了(A,B,C),并隆重推出:
# pseudo code
where(a = value_of a AND b = value of b AND c > value of c).or
where(a = value_of a AND b > value of b).or
where(a > value of a)
这只是它的要点。它也与关联值一起工作,并且聪明地找到前一部分的反向值。为了保持你的搜索状态(或范围组合),你可以使用另一个像siphon的lib,ransack,has_scope等...
下面是来自自述一个working example
模型:
class Book
def nexter=(relation)
@nexter = Nexter.wrap(relation, self)
end
def next
@nexter.next
end
def previous
@nexter.previous
end
end
控制器
class BookController
before_filter :resource, except: :index
def resource
@book_search = BookSearch.new(params[:book_search])
@book ||= Book.includes([:author]).find(params[:id]).tap do |book|
book.nexter = siphon(Book.scoped).scope(@book_search)
end
end
end
的视图:
<%= link_to "previous", book_path(@book.previous, book_search: params[:book_search]) %>
<%= link_to "collection", book_path(book_search: params[:book_search]) %>
<%= link_to "next", book_path(@book.next, book_search: params[:book_search])
```
[钢轨可能重复:“下后“和”普雷维奥我们张贴“链接在我的节目视图,如何?](http://stackoverflow.com/questions/1275963/rails-next-post-and-previous-post-links-in-my-show-view-how- to) – 2014-04-20 11:14:52