使用给定对象查找数据库中的下一个ActiveRecord模型对象

时间:2010-01-13 03:23:28

标签: ruby-on-rails ruby activerecord

我有一个ActiveRecord模型对象@gallery,它代表了Galleries MYSQL表中的一行。有没有办法让我@gallery向我提供表格中下一个画廊对象的ID?

我这样做的显而易见的方法是:

@galleries = Gallery.find(:all)
index = @galleries.index(@gallery)

@nextgallery = @galleries[index+1]

然后我必须nilsafe这个我不必要地进行另一个DB调用来获取所有记录。 还有其他出路吗?

5 个答案:

答案 0 :(得分:8)

我一直处于类似的情况,我最终使用Rails 3.1.3的几个解决方案,使用类方法或范围(Rails 2.x中的named_scope)。即使没有连续的ID,这种方法也能正常工作。

使用Post模型的类方法示例:

def next
  Post.where("posts.id > ?", self.id).order("posts.id ASC").limit(1)
end

def previous
  Post.where("posts.id < ?", self.id).order("posts.id DESC").limit(1)
end

这可以像:

一样使用
post = Post.find(5)

next_post = post.next
 => [#<Post id: 6, ...]

previous_post = post.previous
 => [#<Post id: 4, ...]

对于范围,使用lambda应该是这样的:

  scope :next, lambda { |i| {:conditions => ["#{self.table_name}.id > ?", i.id], :order => "#{self.table_name}.id ASC", :limit => 1} }
  scope :previous, lambda { |i| {:conditions => ["#{self.table_name}.id < ?", i.id], :order => "#{self.table_name}.id DESC", :limit => 1} }

答案 1 :(得分:2)

你真的确定你正在进行第二次数据库调用吗?如果是这样,它真的重要吗?这是否深入4x嵌套循环,每次调用都很重要?

如果没有,预先优化可能是你的垮台。 AR:B做了很多缓存,而iirc find(:all)返回一个数组或Hash,所以index + 1应该没问题。

答案 2 :(得分:2)

首先,您应该定义一些标准来决定您的画廊的顺序。在MySQL中你会做什么

 SELECT * FROM galeries

它可以为您提供不同的退回记录顺序。因此,例如,如果您按创建时间订购它们,那么您可以执行以下操作:

 @nextgallery = Gallery.find(
                   :first, 
                   :order => "created_at ASC", 
                   :conditions => "created_at > #{@gallery.created_at}"
                 )

在此示例中,您应该注意@gallery.created_at,因为Rails以GMT + 0时间格式存储在数据库时间,但在@gallery.created_at中,它与您的本地配置(例如+2 h)一起存储。要更改它,请使用:@gallery.created_at.gmtime.to_s

答案 3 :(得分:0)

您提供的代码是一件好事。 find(:all)方法默认以下列方式提取画廊表的所有记录(在开发模式下运行WEBrick时可以看到它)

SELECT * FROM galleries

每次访问@galaeries时都会缓存并重用此查询的结果,这也是可见的(运行WEBrick时),因为没有进行其他数据库调用。

答案 4 :(得分:0)

我不相信有一种方法可以从你的@gallery实例中获取下一个库,而无需访问数据库。

但是,如果您执行类似

的操作,则只能访问数据库一次
@galleries = Gallery.find(:all)
@gallery = @galleries.detect{|g| g.id == params[:gallery_id]}
index = @galleries.index(@gallery)
@nextgallery = @galleries[index+1]

因此你只打了一次数据库。如果您拥有大量的图库,这只会很糟糕,在这种情况下,将next方法编写到您的图库中会触及数据库是有意义的