A Ruby on Rails will_paginate gotcha

Posted on 16 February 2010

Here's a cheeky gotcha to keep an eye out for when using the popular pagination plugin/gem for Ruby on Rails will_paginate

I was doing something like...

Foo.find(:all, :order => "bar DESC").paginate :page => params[:page]

Looks harmless enough. However, what I didn't realise is that the paginate method cannot run efficiently with the find(:all, ...) method in there.

The whole point of the pagination is to only load the objects you need to for the page, an accompanying sql count allows it to build the links to additional pages.

However, the code above will actually instantiate every single Foo object and load it into memory; nasty.

I tried removing the order to see if that was the problem...

Foo.all.paginate :page => params[:page]

But still it remained inefficient.

The fix was to remove the all method and use the built in paginate :order paramater like so...

Foo.paginate :page => params[:page], :order => "bar DESC"

Now it loads only those objects required for the page.

For a moment I feared how the paginate method had been dealing with named scopes but I can confirm it is happy to work with those and retain its' efficiency, only loading what is required for the page.

Comments left...

  • In all the time I’ve been using will_paginate it has never crossed my mind to even try to call find then paginate :)

    It’s probably worth noting that in the first example you’re calling the paginate method that will_paginate adds to Array objects, and in the last example you’re calling the paginate method on ActiveRecord::Base which works as a kind of proxy to the find method and accepts the usual options like :include, :joins, and :order.

    Rob Anderton at 08 Mar 10 at 12:36

  • As soon as w_p gets Rails3 support, we’ll start being able to use the sexy ARel expressions before the paginate call as well. Score!

    Alexander Bartlow at 08 Mar 10 at 17:00

Got something to say?