I got tired of seeing the deprecation warnings about the old Rails pagination helpers, so I decided to seek out a better approach, but of course I wasn’t going to implement it myself.  With all of the skilled Rails pros out there, I had every intent of leveraging someone’s else’s success.

I succeeded, thanks to Ilya Grigorik and Alex Wolfe.  Ilya wrote “Faster Pagination in Rails” which leverages Alex’ paginating_find plugin to provide limited result sets at the database level.  Ilya’s post includes code he wrote to provide a neat and tidy presentation of the pagination links.

It only took me a few hours to get it working.  It should not have taken this long, but I’m notorious for making things harder than they need to be.  In this case, after I grabbed the code from Ilya’s post and installed the paginating_find plugin for my application, I modified my view to use Ilya’s helper.  This is where it all went wrong.  I was about to do something like this

<%= render :partial => ‘shared/pagination’ %>

but instead did this

<%= windowed_pagination_links(@results) %>

As it turns out neither one of these is correct, but the second one is even more incorrect than the first and led me down a bad path for a couple hours (just what every developer hates).  Since I don’t ever want to repeat that mistake again, and perhaps someone else out there is having this same trouble, I’m writing about it.

What I saw in my functional tests after modifying my view as above (and the associated controller) was

ActionView::TemplateError: undefined method `page’ for #
On line #22 of app/views/sell/list.rhtml

This frustrated me for hours because I couldn’t figure out why it didn’t recognize the page method.  I checked the code, double-checked Ilya’s blog (and many comments) and checked my code to confirm that I was specifying the :page option to the find method.  Sure enough.  Here’s what my controller had

@stuff = Listing.find_by_all_user(session[:user_id],
:page => {:size => 10, :current => params[:page]})

Now if you know about paginating_find, you may notice a problem with the code above.  But since paginating_find was brand new to me, I didn’t notice it.  I’ll explain the problem here shortly.  First let me explain the problem with my view.

What I really needed to have is

<%= render(:partial => ‘shared/paginate’, :locals => {:collection => @stuff}) -%>

So it turns out that I started out on the right path, but left off a critical piece, which is the passing of the controller-returned collection @stuff to the partial so it can do it’s rendering.  If I had even once executed the code using this render(:partial) approach, I’d have been at least on the right path.

Once I got this figured out, I still had problems.  My controller test was still failing with an error like this

ActionView::TemplateError: undefined method `page_count’ for #
On line #2 of app/views/shared/_paginate.rhtml

I returned to Ilya’s blog and read more comments, re-reviewed the entry itself and didn’t see what I was doing wrong.  Then I looked more closely and noticed that all of the references to the use of the paginating_find plugin were using the find() method of any given model.  So I thought perhaps it’s called paginating_find for a reason, that being that it works only with the find() method, not with the Rails dynamic methods find_by_XXX and find_all_by_XXX.  But I was using find_all_by_user (where user is the property of my model that I wanted to find stuff by.

So a quick update to my code fixed the problem and all tests are passing.

@stuff = Stuff.find(:all, :conditions => ['user=?', session[:user_id]],
:page => {:size => results_per_page, :current => params[:page], :first => 1})

Now I’m a happy camper on the Rails.