Search for the next ActiveRecord model object in the database using the specified object

I have an ActiveRecord @gallery model object that represents a row in a MYSQL Galleries table. Is there any way I asked @gallery provide me with an identifier for the next gallery object in the table?

The obvious way to do this is:

 @galleries = Gallery.find(:all) index = @galleries.index(@gallery) @nextgallery = @galleries[index+1] 

but then I have to execute nilsafe and I unnecessarily make another DB call to retrieve all the records. Any other way out?

+4
source share
5 answers

I was in a similar situation, and in the end I got a couple of solutions using Rails 3.1.3 using methods or areas of the class (named_scope in Rails 2.x). This approach will work even with non-sequential identifiers.

An example of class methods using the Post model:

 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 

This can be used as:

 post = Post.find(5) next_post = post.next => [#<Post id: 6, ...] previous_post = post.previous => [#<Post id: 4, ...] 

And for lambda applications, there should be something like:

  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} } 
+8
source

Are you really sure that you are making a second db call? If so, does it really matter? Is this a depth in a 4 nested loop where every call matters?

If not, pre-optimization may be your downfall. AR: B does a lot of caching, and iirc find (: all) returns an array or Hash, so index + 1 should be fine.

+2
source

First of all, you need to define some criteria to determine the order of your galleries. In MySQL, when will you do

  SELECT * FROM galeries 

it may provide you with a different order of returned records. For example, if you order them by creation time, you can do something like this:

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

In this example, you should be careful with @gallery.created_at , because Rails stores the time in the database in GMT +0 format, but in @gallery.created_at it matches your local configuration (for example, +2 h). To change it, use: @gallery.created_at.gmtime.to_s

+2
source

The code you submitted is a good thing. The find(:all) method retrieves all gallery table entries by default as follows (you can see this when WEBrick starts in development mode)

 SELECT * FROM galleries 

The results of this query are cached and reused every time you access @galaeries, this is also visible (when WEBrick starts), since no other database calls are made.

0
source

I do not believe that it is possible to get the following gallery from your @gallery instance without getting into the database.

However, you could only hit the database once if you did something like

 @galleries = Gallery.find(:all) @gallery = @galleries.detect{|g| g.id == params[:gallery_id]} index = @galleries.index(@gallery) @nextgallery = @galleries[index+1] 

Therefore, you enter the database only once. This is bad if you have a large number of galleries, in which case it makes sense to write the next method for your gallery, which falls into the database

0
source

All Articles