Wednesday, February 16, 2011

Paginating custom objects with will_paginate

Moved here

will_paginate makes pagination easy, and we use it whenever we need to show lots of ActiveRecord objects. Once the will_paginate gem is installed, it provides a built-in #paginate method for classes that inherit from ActiveRecord::Base, but we still had our own crazy hacked-up pagination for the responses we would get back from solr. In the interest of making things more consistent and deleting as much code as possible, we thought it'd be a good idea to look into getting our solr objects into the will_paginate model.

This turned out to be much easier than expected. The will_paginate view helper expects an instance of WillPaginate::Collection, which is simple enough to initialize. It was as easy as adding the following method to our search models:

def paginated_docs(options = {})
  WillPaginate::Collection.create(options[:page] || 1, options[:per_page] || PER_PAGE) do |pager|
    
    @response = $solr_client.query(self.search_options.merge({
      :offset => pager.offset,
      :limit => pager.per_page}))
    
    pager.replace(@response.docs)

    # pager.replace sets total_entries if we're on the
    # last page. Otherwise, we'll just populate it.
    unless pager.total_entries
      pager.total_entries = @response.total
    end
  end

As long as a WillPaginate::Collection is returned, will_paginate will do the right thing. Something similar should work for using other services that support limit/offset, but don't have built-in pagination.

No comments: