Rails:获取下一个/上一个记录

时间:2011-09-12 21:10:34

标签: sql ruby-on-rails ruby-on-rails-3

我的应用包含属于用户的照片。

在照片#show视图中,我想显示“来自此用户的更多内容”,并显示该用户的下一张和上一张照片。我可以将这些作为id订单中的下一张/上一张照片或created_at订单中的下一张/上一张照片。

您如何为下一张/上一张照片或多张下一张/上一张照片撰写此类查询?

9 个答案:

答案 0 :(得分:88)

试试这个:

class User
  has_many :photos
end


class Photo
  belongs_to :user

  def next
    user.photos.where("id > ?", id).first
  end

  def prev
    user.photos.where("id < ?", id).last
  end

end

现在你可以:

photo.next
photo.prev

答案 1 :(得分:16)

它也引导我解决我的问题。我试图为一个项目制作下一个/上一个,没有涉及任何关联。最终在我的模型中做了类似的事情:

  def next
    Item.where("id > ?", id).order("id ASC").first || Item.first
  end

  def previous
    Item.where("id < ?", id).order("id DESC").first || Item.last
  end

这种方式循环,从最后一个项目到第一个项目,反之亦然。 我之后只是在我的观点中致电@item.next

答案 2 :(得分:8)

不确定这是否是Rails 3.2+中的更改,而不是:

model.where("id < ?", id).first

以前的。你必须这样做

.where("id > ?", id).last

似乎“order by”是错误的,所以首先给你DB中的第一条记录,因为如果你有3项低于当前的[1,3,4],那么“第一”是1,但最后一个是你正在寻找的那个。您也可以在where之后应用排序,但这是一个额外的步骤。

答案 3 :(得分:3)

class Photo < ActiveRecord::Base
  belongs_to :user
  scope :next, lambda {|id| where("id > ?",id).order("id ASC") } # this is the default ordering for AR
  scope :previous, lambda {|id| where("id < ?",id).order("id DESC") }

  def next
    user.photos.next(self.id).first
  end

  def previous
    user.photos.previous(self.id).first
  end
end

然后你可以:

photo.previous
photo.next

答案 4 :(得分:2)

您可以将一些选项传递给where方法:

下一张照片:

Photo.where(:user_id => current_user.id, :created_at > current_photo.created_at).order("created_at").first

上一张照片

Photo.where(:user_id => current_user.id, :created_at < current_photo.created_at).order("created_at").last

我可能有第一个/最后一个混淆。

答案 5 :(得分:1)

您可能需要查看Nexter。 它适用于任何动态创建的范围,而不是依赖于模型中的一个硬编码。

答案 6 :(得分:1)

class Photo < ActiveRecord::Base
  belongs_to :user

  default_scope { order('published_at DESC, id DESC') }

  def next
    current = nil
    user.photos.where('published_at >= ?', published_at).each do |p|
      if p.id == id then break else current = p end
    end
    return current
  end

  def previous
    current = nil
    user.photos.where('published_at <= ?', published_at).reverse.each do |p|
      if p.id == id then break else current = p end
    end
    return current
  end
end

我发现这里的答案不符合我的要求。想象一下,你想要一个基于发布日期的前一个或下一个,但有些照片是在同一个日期发布的。这个版本将按照它们在页面上呈现的顺序循环遍历照片,并在集合中的当前照片之前和之后拍摄。

答案 7 :(得分:1)

这应该有效,我认为它比其他解决方案更有效,因为它不会检索每个记录高于或低于当前记录只是为了到达下一个或前一个记录<: / p>

def next
  # remember default order is ascending, so I left it out here
  Photo.offset(self.id).limit(1).first
end

def prev
  # I set limit to 2 because if you specify descending order with an 
  # offset/limit query, the result includes the offset record as the first
  Photo.offset(self.id)limit(2).order(id: :desc).last
end

这是我在StackOverflow上发布的第一个答案,这个问题很老了...我希望有人看到它:)

答案 8 :(得分:0)

将您的app / models / application_record.rb修改为以下代码:

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true

  def next
    self.class.where("id > ?", id).order("id ASC").first || self.class.first
  end

  def previous
   self.class.where("id < ?", id).order("id DESC").first || self.class.last
  end
end

然后,您可以在所有模型中使用next()和previous()。