Autonomous Machine

Using will_paginate with DataMapper and Sinatra

Yes, it can be done. But not using prebuilt gems, since we need to use the agnostic branch of the will paginate repository for DataMapper support. Here's what I did to install the necessary version of will_paginate:

git clone git://github.com/mislav/will_paginate.git
cd will_paginate
git checkout --track -b agnostic origin/agnostic # check out agnostic branch
gem build will_paginate.gemspec # build the gem
sudo gem install will_paginate-3.0.0.gem # install the gem

You could also create a fork, merge the code from agnostic into the master branch, push to GitHub, and have your own username-will_paginate gem to install. I decided this wasn't worth the effort, at least for the project I was working on.

Models

When will_paginate is required, it does some checks to see if it is running under Rails or Merb, and if so, mixes the class methods and view helpers into the base classes for you. If you're working with another framework (such as Sinatra), you'll need to require the finders and view helpers on your own:

require 'will_paginate'
require 'will_paginate/finders/data_mapper'

At this point, YourModelName#paginate will return paginated collections. But we need to be able to render pagination links as well...

Views

will_paginate has abstracted out the view logic into a few modules, and all it depends on is the implementation of the WillPaginate::ViewHelpers::LinkRenderer#url method. To get the view helper working, I added the following to the bottom of my Sinatra app's file (based on the supplied the merb adapter):

require 'will_paginate/view_helpers/base'
require 'will_paginate/view_helpers/link_renderer'

WillPaginate::ViewHelpers::LinkRenderer.class_eval do
  protected
  def url(page)
    url = @template.request.url
    if page == 1
      # strip out page param and trailing ? if it exists
      url.gsub(/page=[0-9]+/, '').gsub(/\?$/, '')
    else
      if url =~ /page=[0-9]+/
        url.gsub(/page=[0-9]+/, "page=#{page}")
      else
        url + "?page=#{page}"
      end      
    end
  end
end

helpers WillPaginate::ViewHelpers::Base

The code assumes the page number will be in the query string; it could easily be modified to work in other situations.