Rails:上一个查询的上一个和下一个记录

问题描述:

我的应用有照片,用户可以搜索符合特定条件的照片。我们先来说说照片用户搜索的标签,而我们得到的东西是这样的:Rails:上一个查询的上一个和下一个记录

@results = Photo.tagged_with('mountain') 

现在,@results将是一个标准的ActiveRecord查询与多个记录。这些将显示在网格中,然后用户可以点击照片。这将使用户执行photos#show操作。

因此,可以说用户搜索某物,应用程序找到5条记录,[1,2,3,4,5],用户点击照片#3。

photo#show页面上,我希望能够显示“下一张照片”,“上一张照片”和“返回搜索”。

唯一的另一个限制是,如果用户直接浏览照片(通过另一个页面或书签等),则不会有逻辑的“下一张”和“上一张”照片,因为没有查询将他们引导至该照片,因此在这种情况下,该模板根本不应呈现与查询相关的内容。

所以,我一直在想如何做这种事情,我真的没有太多好主意。我想我可以做一些事情,比如在会话中存储查询,以便能够回到它,但我不知道如何找到显示在所选照片的​​左侧和右侧的照片。

有没有人有任何如何做这种事情的例子?

+0

[钢轨可能重复:“下后“和”普雷维奥我们张贴“链接在我的节目视图,如何?](http://*.com/questions/1275963/rails-next-post-and-previous-post-links-in-my-show-view-how- to) – 2014-04-20 11:14:52

所以,大量的试验和错误之后,这里是我想出了:

在我的照片模式:

# 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或书签)到另一张属于先前查询的照片,查询将会保留在会话中,并且相关照片链接仍将在第二张照片上可见 - 即使他们不应该在通过书签加载的照片上。

但是,在现实生活中,这种情况实际上很难重新创建,而且代码目前运行良好。在某个时候,当我为剩下的那个问题想出一个很好的解决方案时,我会发布它,但是现在如果有人使用这个想法,请注意可能存在。

+0

您可以通过将持久查询的id放入下一个/上一个链接的url以及搜索页面中的链接来解决您的_gotcha_。这样,如果您看到ID并且它与最后一个持续查询匹配,则显示下一个/上一个按钮。如果由于用户输入了URL或以另一种方式到达了页面,ID不在那里,请不要显示按钮。 – 2011-04-13 20:19:05

+0

@Brian:哦!这是一个很酷的想法,我会努力实现这样的事情! – Andrew 2011-04-13 20:36:48

+0

非常感谢发布这个,它真的很有用。 – snowangel 2011-07-01 07:17:59

你可以看看在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 
+0

这不*做我想做的事情。我不只是想要下一张照片,我希望来自特定用户最近搜索结果的下一张照片。我相信我的方法并不完美,我列出了我最知名的“疑难杂症”,但它在我的应用程序中按需要工作。 – Andrew 2012-03-01 03:03:14

+1

它没有做他想做的事,但它对我来说是完美的:) – Arcolye 2012-03-14 08:49:09

+0

对我来说,使用Rails 4这个工作并不合适。你的“下一个”给了我“最后”和“之前”给我的第一个。 – 2014-02-14 23:38:59

一个我编写的名为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]) 
```