Rails:获取下一个/上一个记录
Posted
技术标签:
【中文标题】Rails:获取下一个/上一个记录【英文标题】:Rails: Get next / previous record 【发布时间】:2011-09-12 21:10:34 【问题描述】:我的应用有属于用户的照片。
在 photo#show 视图中,我想显示“来自该用户的更多信息”,并显示该用户的下一张和上一张照片。我可以将这些作为id
订单中的下一张/上一张照片或created_at
订单中的下一张/上一张照片。
您将如何为下一张/上一张照片或多张下一张/上一张照片编写这种查询?
【问题讨论】:
这颗宝石非常适合我。 ***.com/a/25712023/683157 【参考方案1】:试试这个:
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
【讨论】:
prev 这种方式不能正常工作,应该是 user.photos.where("id @igrek 我已经确定了答案。一般来说,我避免使用last
调用,因为如果您有一个大数据集(***.com/questions/4481388/…),它会影响性能。我使用ORDER BY id DESC
子句到达最后一行。
使用limit(1)怎么样?
@KourindouHime,first
方法将结果集限制为LIMIT 1
。这里的first
方法与数组上的第一种方法不同。
@igrek,我已将解决方案更改为使用first
和last
,因为我注意到在最新版本的rails 中first
和last
添加了正确的排序。【参考方案2】:
它也让我找到了解决问题的方法。我试图为一个项目制作下一个/上一个,不涉及任何关联。最终在我的模型中做了这样的事情:
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
。
【讨论】:
循环迭代很棒。 不错,也在找循环!【参考方案3】:不确定这是否是 Rails 3.2+ 中的更改,但不是:
model.where("id < ?", id).first
为上一个。你必须这样做
.where("id > ?", id).last
看来“order by”是错误的,所以先给你DB中的第一条记录,因为如果你有3项低于当前,[1,3,4],那么“第一”是1,但最后一个是你要找的那个。您也可以在 where 之后应用排序,但这是一个额外的步骤。
【讨论】:
【参考方案4】: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
【讨论】:
【参考方案5】:这应该可行,而且我认为它比其他解决方案更有效,因为它不会检索当前记录之上或之下的每条记录,只是为了获取下一个或上一个记录:
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
这是我在 *** 上发布的第一个答案,而且这个问题已经很老了......我希望有人看到它:)
【讨论】:
如果底层数据库 ID 不规则(这是一个常见用例),此解决方案将不起作用。例如,如果我的记录 ID 是[3, 10, 11, 13, 14]
,并且如果我想找到 id => 3
的下一个元素,那么生成的结果是 offset(3) => [13,14]
。这种行为在文档offset => Specifies the number of rows to skip before returning rows.
中有清楚的解释【参考方案6】:
您可以将一些选项传递给 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
我可能把第一个/最后一个弄混了。
【讨论】:
【参考方案7】:将你的 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()。
【讨论】:
效果很好。您可能希望在您的模型类上实现这一点,这样您就可以以与您的业务逻辑一致的方式(例如,下一篇/上一篇发表的文章)限定查询范围。【参考方案8】:您可能想查看Nexter。 它适用于任何动态创建的范围,而不是依赖于模型中的硬编码。
【讨论】:
我创建了具有相同行为的 gem,但另一种方法:github.com/dmitry/proximal_records【参考方案9】: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
我发现这里已经给出的答案不适合我的情况。想象一下,您想要基于发布日期的上一张或下一张,但有些照片是在同一日期发布的。此版本将按照片在页面上呈现的顺序循环播放照片,并获取集合中当前照片之前和之后的照片。
【讨论】:
以上是关于Rails:获取下一个/上一个记录的主要内容,如果未能解决你的问题,请参考以下文章
Rails N + 1查询问题时获取与where条件关联的记录
获取 STI 中的记录以获取 rails 4 中的空 has_many 记录