DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Paginate An Already-fetched Result Set (i.e. Collection Or Array)

06.16.2005
| 35415 views |
  • submit to reddit
        Sometimes it's nearly impossible to paginate a result set using the built-in :limit and :offset parameters of find(:all). Instead, you can fetch a complicated query and paginate the results afterward.

Add the following to application.rb:

  def paginate_collection(collection, options = {})
    default_options = {:per_page => 10, :page => 1}
    options = default_options.merge options
    
    pages = Paginator.new self, collection.size, options[:per_page], options[:page]
    first = pages.current.offset
    last = [first + options[:per_page], collection.size].min
    slice = collection[first...last]
    return [pages, slice]
  end

Call it from within your action like this:
@pages, @users = paginate_collection User.find_custom_query, :page => @params[:page]
    

Comments

Snippets Manager replied on Tue, 2007/10/30 - 6:46am

Thanks, works fine for me. :)

Snippets Manager replied on Tue, 2006/09/19 - 6:34am

hi actually i needed some help. i ve made a search engine for some xyz website.. now i need 2 paginate the resultanat variable. say @programme variable. It contains my search result n i need 2 paginate @programme variable. but since the search engine doesnt ve any resp. model it has only controller i m unable to use either paginate helper or paginate by sql for the same. kindly guide me as on how to paginate a particular variable. Thanx n Regards, Neha Gupta

Snippets Manager replied on Thu, 2006/02/02 - 4:07pm

I added this: options[:page] = options[:page] || params[:page] || 1 so that I don't need to specify :page => @params[:page] all the time. It looks like this now: def paginate_collection(collection, options = {}) options[:page] = options[:page] || params[:page] || 1 default_options = {:per_page => 10} options = default_options.merge options

Snippets Manager replied on Mon, 2012/05/07 - 2:12pm

There's definitely a performance hit. You only want to do this kind of pagination when you're sure the result set won't become crazy huge. I suspect we'll be seeing some much better pagination support in the Rails core soon (or at least via plugins).

Snippets Manager replied on Mon, 2012/05/07 - 2:12pm

A modification on the above that allows block syntax (which can eliminate a temp in most cases) # Paginates an existing AR result set, returning the Paginator and collection slice. # # Based upon: # http://www.bigbold.com/snippets/posts/show/389 # # Options: # +:collection+: the collection to paginate # +:per_page+: records per page # +:page+: page # # Example: # complex_query_result = Customer.find_by_sql('something complex') # @pages, @customers = paginate_collection(:collection => complex_query_result) # # Alternatively, you can specify a block, the result of which will be used as the collection: # @pages, @customers = paginate_collection { Customer.find_by_sql('something complex') } def paginate_collection(options = {}, &block) if block_given? options[:collection] = block.call elsif !options.include?(:collection) raise ArgumentError, 'You must pass a collection in the options or using a block' end default_options = {:per_page => 10, :page => 1} options = default_options.merge options pages = Paginator.new self, options[:collection].size, options[:per_page], options[:page] first = pages.current.offset last = [first + options[:per_page], options[:collection].size].min slice = options[:collection][first...last] return [pages, slice] end

Snippets Manager replied on Mon, 2012/05/07 - 2:12pm

Is there a performance issue with getting a potentially large result set and then paginating afterwards? Or is it fine because the results are stored into memory (in a fcgi environment?)?? Thanks.

Snippets Manager replied on Mon, 2012/05/07 - 2:12pm

Done.

Snippets Manager replied on Mon, 2012/05/07 - 2:12pm

Thanks, that's very useful! Can you please put a "rails" and "ruby" tag on it?