For pagination to work, you’ll need to submit the desired page number along with the search conditions. In this post, I will discuss how to add pagination for Ransack forms that use the POST method.

Ransack forms typically use the GET method, and pagination gems like will_paginate append query parameters to the pagination links. Use POST when the Ransack form contains several fields because the length of the resulting query params might exceed the allowable URL length. This length varies by browser.

Suppose we have the following Rails view with will_paginate:

<!-- Ransack form with POST -->
<%= search_form_for(@search, url: advanced_search_users_path, 
html: { method: :post, class: 'ransack-form' }) do |f| %>
...
<%= f.submit class: 'btn btn--invert' %>
<% end %> 

<!-- search results using will_paginate -->
<table class="results">
  <thead>
    <th>Name</th>
    <th>Email</th>
  </thead>
  <tbody>
    <% @users.each do |user| %>
    <tr>
      <td>@user.name</td>
      <td>@user.email</td>
    </tr>
    <% end %>
  </tbody>
</table>

<div class="ransack-pagination">
  <%= will_paginate @users %>
</div>

The pagination links do not include the Ransack query parameters because we use POST. Clicking a link should therefore submit the form together with page number. We can use JavaScript (CoffeeScript) to accomplish this. First, let’s add a hidden field to the form for the page number:

<%= search_form_for(@search, url: advanced_search_users_path, 
html: { method: :post }) do |f| %>
...
<%= hidden_field_tag 'page', '1', {class: 'ransack-page'} %>
<% end %> 

On our controller, we use the params[page] for pagination:

def index    
  @search = User.ransack(params[:q])
  @search.build_condition
  @search.build_grouping unless @search.groupings.any?
     
  @users = @search.result.order("name asc").paginate(:page => params[:page])
end

Now, we add the following CoffeeScript to get the page number we want (line 2); change the value of the hidden field (line 3); and submit the form (line 4):

1
2
3
4
5
$(document).on "click", "div.ransack-pagination a", (event) ->
  pageNum = $(this).attr("href").match(/page=([0-9]+)/)[1]
  $('.ransack-page').val(pageNum)
  $('form.ransack-form').submit()
  event.preventDefault() 

A drawback of this approach is that if the user changes the search parameters and then subsequently clicks on a pagination link, the altered form is submitted. This means that a new search is submitted, even though the “Submit” button was not explicitly clicked. Let’s call this a feature instead of a bug :)