Ok, Ferret is great, but how to paginate?

I saw several solutions on the net and liked this one the most.

It appears that it’s quite easy to integrate acts_as_ferret with will_paginate, the officially recommended pagination plugin for Rails.

First, a patch is needed. I placed it to a new file in my special place for patches, vendor/plugins/patches/lib; it could also go in some of existing application files, e.g. bottom of environment.rb:


module ActsAsFerret
  module ClassMethods
    alias :find_all_by_contents :find_by_contents
  end
end

Then, in controller:


@users = User.paginate_by_contents(@search.query,
  :total_entries => User.total_hits(@search.query), :page => params[:page],
  :per_page => 10)

Change User to your model class here. You can also use sorting here, see Tutorial below for guidelines.

The trick is that will_paginate is friendly to model class’s methods like find_all_by_xxx; acts_as_ferret’s find_by_contents’s name is a bit wrong for it, so we make an alias, and later this method becomes our model’s method, when we put acts_as_ferret statement in the model class definition.

References:

  • Acts_As_Ferret Tutorial
  • This solution was taken from will_paginate’s author blog, thanks ocher!


5 Responses to “acts_as_ferret pagination”  

  1. 1 Liam

    I placed the first set of code that you posted into ‘vendor/plugins/patches/lib’ and then entered the following in the console (after restarting the console). Any clues to what’s wrong here?

    t = Post.paginate_by_contents(‘test’, :total_entries => 10, :page => 1, :per_page => 2)
    NoMethodError: undefined method `find_all_by_contents’ for #
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.1.0/lib/active_record/base.rb:1613:in `method_missing_without_paginate’
    from /Users/liamks/Documents/programs/rails/liamkaufman/vendor/plugins/will_paginate/lib/will_paginate/finder.rb:164:in `method_missing’
    from /Users/liamks/Documents/programs/rails/liamkaufman/vendor/plugins/will_paginate/lib/will_paginate/finder.rb:82:in `send’
    from /Users/liamks/Documents/programs/rails/liamkaufman/vendor/plugins/will_paginate/lib/will_paginate/finder.rb:82:in `paginate’
    from /Users/liamks/Documents/programs/rails/liamkaufman/vendor/plugins/will_paginate/lib/will_paginate/collection.rb:87:in `create’
    from /Users/liamks/Documents/programs/rails/liamkaufman/vendor/plugins/will_paginate/lib/will_paginate/finder.rb:76:in `paginate’
    from /Users/liamks/Documents/programs/rails/liamkaufman/vendor/plugins/will_paginate/lib/will_paginate/finder.rb:177:in `method_missing’
    from (irb):1

  2. 2 thirstydoh

    Looks like the patch file is not loaded. You need to put its name into vendor/plugins/patches/init.rb file, like this:

    require ‘aaf_pagination’

    Note you don’t need to mention lib directory there, it’s searched automatically.

  3. 3 Liam

    Thanks for your reply!

    I tried your suggestion and all the errors went away, however, all my search queries turn up nothing. Every single search combo in the console returns:

    I decided to uninstall will_paginate plugin and install the mislav-will_paginate gem and use the built in pagination of ferret with the following method:

    http://www.jumbabox.com/2008/05/acts_as_ferret-tutorial/

    Unfortunately, that technique also returns nothing when I run a query… Given that the null findings occured in the new technique and the technique you suggested I was wondering if you have any ideas on how to remedy it?

  4. You might want to try to use less magic and monkey patching, and just use the two APIs together.

    def self.paginate_by_contents(term, opts)
    self.paginate(term, {:finder => “find_by_contents”, :total_entries => self.total_hits(term)}.merge(opts || {}))
    end

  5. In Rails 2.3 you have to make sure you load acts_as_ferret, will_paginate, and the patch in the right order. In order for me to get this working, I had to put require ‘acts_as_ferret’ above the initialize loop in environment.rb. If I didn’t, the patch would load before acts_as_ferret and result in an error.


Leave a Reply