我有一个ActiveRecord模型对象@gallery
,它代表了Galleries MYSQL表中的一行。有没有办法让我@gallery
向我提供表格中下一个画廊对象的ID?
我这样做的显而易见的方法是:
@galleries = Gallery.find(:all)
index = @galleries.index(@gallery)
@nextgallery = @galleries[index+1]
然后我必须nilsafe这个我不必要地进行另一个DB调用来获取所有记录。 还有其他出路吗?
答案 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
方法编写到您的图库中会触及数据库是有意义的