Rails 3.1 - will_paginate and AJAX

November 10, 2011


This post was originally published in the Rambling Labs Blog on November 10, 2011.


For a project that I’m currently working on, I have a couple of list views that needed pagination. So I went with the ol’ will_paginate gem (which I first saw years ago when I didn’t even consider myself a developer) to take care of this.

It’s as simple as including a line with gem 'will_paginate' on your Gemfile, running bundle install, and include this in the controller:

class OrdersController < ApplicationController
  def index
    @orders = Order.paginate(page: params[:page], per_page: 10)
  end
end

And this in the view orders/index.html.erb:

<div id="orders">
  <ul>
    <% @orders.each do |order| %>
      <li>
          <!-- Show order stuff -->
      </li>
    <% end %>
  </ul>
  <%= will_paginate @orders %>
</div>

Now, this last line will generate your pagination links. Then, a problem arose. There was one specific view which I didn’t want to be refreshed completely when clicking the pagination links.

Partials, jQuery and AJAX to the rescue

I found a post (in a blog with a really familiar name), which described a way to do it that just seemed magical. But that combined with a stack overflow question that I found, seems to be the way to go. Here is what I did:

In the controller:

class OrdersController < ApplicationController
  def index
    @orders = Order.paginate(page: params[:page], per_page: 10)
  end
end

Encapsulate the order list in the partial view orders/_orders.html.erb:

<ul>
  <% @orders.each do |order| %>
    <li>
        <!-- Show order stuff -->
    </li>
  <% end %>
</ul>
<%= will_paginate @orders %>

The resulting index view orders/index.html.erb:

<div id="orders">
  <%= render partial: 'orders' %>
</div>

The view orders/index.js.erb:

$('#orders').html('<%= render partial: 'orders' %>');
$.setAjaxPagination();

The JavaScript (CoffeeScript) file assets/orders.js.coffee:

$ ->
  $.setAjaxPagination = ->
    $('.pagination a').click (event) ->
      event.preventDefault()
      loading = $ '<div id="loading" style="display: none;"><span><img src="/assets/loading.gif" alt="cargando..."/></span></div>'
      $('.other_images').prepend loading
      loading.fadeIn()
      $.ajax type: 'GET', url: $(@).attr('href'), dataType: 'script', success: (-> loading.fadeOut -> loading.remove())
      false

  $.setAjaxPagination()

And that’s it! Fairly easy I would say!