Using paginating_find with has_finder

Alon Salant ·

I’ve been enjoying using has_finder by Nick at Pivotal Labs and recently added pagination to the application I am providing volunteer time to for the San Francisco Bike Kitchen.

I like the semantics of paginating_find over will_paginate but am not married to that choice if anyone wants to try to convince me otherwise.

In any case, I wanted to paginate the finders created by has_finder. I wrote a simple ActiveRecord mixin that provides a class method ‘acts_as_paginated and is used in your model like:

class Visit  10

  has_finder :for_person, lambda { |person| {
    :conditions => { :person_id => person},
    :order => 'datetime DESC'
  } }

  has_finder :in_date_range, lambda { |from,to| {
    :conditions => [ "visits.datetime >= ? and visits.datetime <= ?", from, to ]
  } }
end

Client code looks like:

from, to = Date.new(2008,2,1), Date.new(2008,2,3)
visits = Visit.for_person(@person).in_date_range(from, to).paginate(:page => 3)

The mixin looks like:

# Provides Model.paginate(options={}) to allow
# the paginating_find plugin to be used with the has_finder plugin.
#
# Usage:
#   acts_as_paginated
#   acts_as_paginated :page => 2, size => 10
#
# Install:
#   Save this file as lib/acts_as_paginated.rb and require 'acts_as_paginated'
#   in environment.rb.
#
module HasFinder
module PaginatingFind #:nodoc:

def self.included(mod)
  mod.extend(ClassMethods)
end

module ClassMethods
  def acts_as_paginated(options={ :page => 1, :size => 20})
    cattr_accessor :paginate_defaults
    self.paginate_defaults = options

    self.class_eval do
      extend HasFinder::PaginatingFind::SingletonMethods
    end
  end
end

module SingletonMethods
  def paginate(args={})
  options = self.paginate_defaults.clone
    options[:page] = args[:page].to_i if args[:page]
      options[:size] = args[:size].to_i if args[:size]
        find(:all, :page => { :size => options[:size], :current => options[:page], :first => 1 })
      end
    end
  end
end

ActiveRecord::Base.send(:include, HasFinder::PaginatingFind)

It also works to paginate associations:

@person.visits.paginate(:size => 4)