Using will_paginate with acts_as_solr

Written . Tagged Ruby, Ruby on Rails.

Still playing with Solr/acts_as_solr.

The site I’m working on uses will_paginate for pagination. It turned out to be pretty easy to get that working with results from acts_as_solr.

The solution is to add a find_all_by_solr method that wraps find_by_solr and returns the records of the returned SearchResults.

Stick solr_pagination.rb in lib in your Rails project.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# By Henrik Nyh <http://henrik.nyh.se> 2007-06-18.
# Free to modify and redistribute with credit.

# Adds a find_all_by_solr method to acts_as_solr models to enable
# will_paginate for acts_as_solr search results.

module ActsAsSolr
  module PaginationExtension

    def find_all_by_solr(*args)
      find_by_solr(*args).records
    end

  end
end

module ActsAsSolr::ClassMethods
  include ActsAsSolr::PaginationExtension
end

Then ensure that this code is actually run, by adding

1
require 'solr_pagination'

to config/environment.rb. It wouldn’t work at the bottom of that file, so I stuck it just before

1
Rails::Initializer.run do |config|

If you want to verify that things work so far, (re)start the script/console and try something like SomeModel.find_all_by_solr("foo", {:limit => 5, :offset => 2}).

And that’s the plumbing done.

You want a controller action like

1
2
count = SomeModel.count_by_solr(params[:query])
@results = SomeModel.paginate_all_by_solr(params[:query], :page => params[:page], :total_entries => count)

and a view like

1
2
3
4
5
6
7
8
<dl>
<% @results.each do |result| %>
  <dt><%= result.title %></dt>
  <dd><%= result.description %></dd>
<% end %>
</dl>

<%= will_paginate @results %>

Note that the :total_entries must be specified explicitly to paginate_all_by_solr. find_all_by_solr isn’t a regular finder, so will_paginate can’t just do a SQL COUNT.

Update 2007-06-18
Today’s 0.9 release of acts_as_solr made things easier. The code above has been updated. Below is the old 0.8.5 version of solr_pagination.rb, which had to translate :limit and :offset (used by regular ActiveRecord finders) into :rows and :start (used by find_by_solr), and that got the records directly rather than in a records attribute.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# By Henrik Nyh <http://henrik.nyh.se> 2007-06-15.
# Free to modify and redistribute with credit.

# Adds a find_all_by_solr method to acts_as_solr models to enable
# will_paginate for acts_as_solr search results.

module ActsAsSolr
  module PaginationExtension

    def find_all_by_solr(query, options)
      map = {:limit => :rows, :offset => :start}
      map.each do |from, to|
        options[to] = options[from]
        options.delete(from)
      end
      find_by_solr(query, options)
    end

  end
end

module ActsAsSolr::ClassMethods
  include ActsAsSolr::PaginationExtension
end