Tuesday 1 June 2010

Iterating through records

Occasionally, you want to be able to go through the records in a table one by one, i.e., from a page showing one record, you want to be able to jump to the next or previous record. One way I have seen to do this is with named_scopes. i like named_scopes, but really, they are not the solution in this case; a simple method for the model is more elegant. Compare:
Post.forward(@post)[0]
@post.forward

Note that a named_scope returns an array. Also, I have called the method forward, as next is a keyword in Ruby. Here are the two methods to go either way.
def forward
Post.find(:all, :conditions => ["id > ?", id], :limit => 1, :order => "id ASC")[0]
end

def back
Post.find(:all, :conditions => ["id < ?", id], :limit => 1, :order => "id DESC")[0]
end

If you want a looped list, you can use these two methods, which will loop around to other end of the list. They use the fact that nil is taken as false, and that Ruby uses lazy evaluation for Boolean arithmetic. he scond part of the expression is only evaulated if the first works out to be nil. There is also a random method, so you can jump around the list. I have made this a class method so you can also jump into a random point in the list.
def forward
Post.find(:all, :conditions => ["id > ?", id], :limit => 1, :order => "id ASC")[0] || Post.find(:first, :order => "id ASC")
end

def back
Post.find(:all, :conditions => ["id < ?", id], :limit => 1, :order => "id DESC")[0] || Post.find(:first, :order => "id DESC")
end

def self.random
Post.find(:first, :offset =>rand(Post.count :all))
end

On your show view, add links like this:

<%= link_to 'Previous', :id => @post.back %> |
<%= link_to 'Random', :id => Post.random %> |
<%= link_to 'Next', :id => @post.forward %>



Struggling with Ruby: Contents Page