parm530
12/5/2017 - 3:22 PM

Pagination in Rails

Using the Kaminari gem to paginate

Pagination

  • Useful when your model contains many items that you would like to organize by displaying a few items at a time
  • Accomplished by using the ruby gem, kaminari
#add gem to gemfile
gem 'kaminari'
  • Run bundle
  • Kaminari provides a page scope that can be used on any ActiveReccord model (use the params params[:page] for this scope)
#usage 
class ProductsController < ApplicationController
  def index
    @products = Product.order("name").page(params[:page])
  end
end
  • In the index view page where you are listing the items of the model:
# before any relevant code
<%= paginate @products %>

# other relevant code ...
  • The default item count per page is 25!
  • This can be adjusted using another scope method that can be chained on to page, called per. You can pass in the number of items per page as it's arguments.
  • Must call page first on the ActiveRecord model.
#usage 
class ProductsController < ApplicationController
  def index
    @products = Product.order("name").page(params[:page]).per(5)
  end
end
  • For more customizations (changing the word "prev" to something else)
    • locate theen.yml file in config/locales/en.yml
# should contain the following
en:
  hello: "Hello world"

# you can add the following:
  views:
    pagination:
      previous: "&lt; Previous"
      next: "Next &gt;"
      truncate: "..." # default style is 3 dots
      

Using Kaminari on non ActiveRecord array:

# if the array you are using is not an ActiveRecord array, but a generic ruby array
# you can still paginate the array by ading on the following:
@array = Kaminari.paginate_array(generic_array).page(params[:page]).per(4)

Incorporate AJAX inside Pagination

  • Set the Kaminari gem (follow instructions above)
  • For the main action (for example index) that contains the table (or thing to be paginated), make sure it responds_to a format block with options for html and js
  • Make sure there are views index.html and index.js!
  • In the action that does an ajax call that manipulates the DOM, (ex. table_sort), make sure that it respond_to :js!
# in your .js.erb file:
$("#team-quote-table-body").html("<%= j render partial: 'team_quotes', locals: {team_quotes: @team_quotes} %>");

$('#paginator').html("<%= escape_javascript(paginate(@team_quotes, :remote => true).to_s) %>");
  • IMPORTANT: Make sure to wrap <%= paginate @model %> is WRAPPED in a div with an id of paginator!
<div id="paginator">
    <% if @team_quotes && @team_quotes.length > 0 %>
        <%= paginate @team_quotes, :remote => true %>
    <% end %>
</div>
  • If you error undefined method current_page for #: this means the page method is not being called on the collection being returned, recheck to see if your later sql calls alter the results:
@team_quotes = Fsi::Quote.where(quote_manager_id: @quote_manager.id).page(params[:page]).per(2)    #calling it here is safe

# Click on the icon, check for header and sort
if !params["header"].blank? && !params["sort"].blank?
    # check for the search param
    if !params["search_term"].blank? 
        search = !params["search_term"].blank? ? params["search_term"] : ""
        @team_quotes = @team_quotes.quick_search(search)

    end

    db_fields = {
        "Created" => "created_at",
        "Sales Rep" => "sales_rep"
    }

    header = db_fields[params["header"]]
    sort = params["sort"].upcase if params["sort"]
    @team_quotes = @team_quotes.order_by_created(sort) if header == "created_at"
    @team_quotes = @team_quotes.order_by_sales_rep(sort) if header == "sales_rep"
else
    # ONLY SEARCH
    if !params["search_term"].blank? 
        search = !params["search_term"].blank? ? params["search_term"] : ""
        @team_quotes = @team_quotes.quick_search(search)
    end

end