Contents
- Japanese Edition
- 1. Environment
- 2. Requirements
- 3. Gemfile
- 4. Config
- 5. Controllers
- 6. Views
- 7. Assets
⚓ 1. Environment
- WSL(Ubuntu 20.04.1 LTS (GNU/Linux 4.19.128-microsoft-standard x86_64))
- ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-linux]
- Rails 6.0.3.4
- Docker version 19.03.13, build 4484c46d9d
⚓ 2. Requirements
- Sustain pagination data for such extensions as Ransack search form introduction
- Show the number of items of all
- Default number of items is 20
- Switch the number of items among 20, 50, 100, 200 and 500
⚓ 3. Gemfile
Add rails-i18n
and kaminari
in Gemfile and run docker-compose exec app bin/rails bundle
.
source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '2.7.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '~> 6.0.3', '>= 6.0.3.2' ... # Locale gem 'rails-i18n', '~> 6.0.0' # Pagination gem 'kaminari', '~> 1.2.1'
⚓ 4. Config
⚓ 4-1. Settings
Define number_per_page
in /config/settings.yml to switch the number of items to show.
common: &common number_per_page: [20, 50, 100, 200, 500] development: <<: *common test: <<: *common staging: <<: *common production: <<: *common
⚓ 4-2. Initializers
First, efine AppConfig
constant in /config/initializers/app_constants.rb to call number_per_page
.
AppConfig = YAML.load_file("#{Rails.root}/config/settings.yml")[Rails.env].symbolize_keys
Next, define the default number of items to show as 20 in /config/initializers/kaminari_config.rb.
Kaminari.configure do |config| config.default_per_page = 20 end
⚓ 4-3. Locales
Define translation of English words of kaminari in /config/locales/pagination.ja.yml.
ja: views: pagination: first: "最初へ" last: "最後へ" previous: "前へ" next: "次へ" truncate: "…" helpers: page_entries_info: one_page: zero: "該当データがありません。" one: "1-1/全1件" display_entries: '1-%{count}/全%{count}件' more_pages: display_entries: '%{first}-%{last}/全%{total}件'
⚓ 5. Controllers
⚓ 5-1. ApplicationController
Define some private methods in /app/controllers/application_controller.rb.
class ApplicationController < ActionController::Base ... private # Return the number of items to show if it is assigned def paginate_per session[:paginate_per] = params[:per] if params[:per].present? session[:paginate_per] end # Sustain query parameters controller name and action name in the key `last_pagination_data` of session def keep_last_pagination_data session[:last_pagination_data] = { params: request.query_parameters, controller: controller_name, action: action_name } end # Abandon `session[:last_pagination_data]` and return `session[:last_pagination_data]["params"]` # if `session[:last_pagination_data]` is NOT `nil`, # `session[:last_pagination_data]["controller"]` is `controller_name` and # `session[:last_pagination_data]["action"]` is `action.to_s` def load_pagination_params(action) data = session[:last_pagination_data].presence if data["controller"] == controller_name && data["action"] == action.to_s session[:last_pagination_data] = nil ret = data["params"] end end # Redirect to the index page with `action: action_name` and `params: session[:last_pagination_data]["params"]` key & values def redirect_with_kept_pagination_params(action:, **args) redirect_to({ action: action, params: load_pagination_params(action) }, args) end end
⚓ 5-2. Apply Pagination to Controllers
Apply paginate_per
private methods to the argument of per
method of kaminari in the controllers you would like to apply pagination to.
def index @events = Event.page(params[:page]).per(paginate_per).where('start_at >= ?', Time.now).order(:start_at) end
⚓ 6. Views
⚓ 6-1. Pagination Header
Implement a shared pagination header in /app/views/shared/_pagination_header.html.erb
<% if defined?(objects) %> <div class="pagination-field"> <div class="pagination-wrapper"> <div class="entry-content"> <%= page_entries_info(objects, entry_name: objects&.model_name.to_s) %> <p class="display-items"> 表示件数: <% AppConfig[:number_per_page].each do |per| %> <%= link_to_unless per == objects.limit_value, per, params.permit!.merge(per: per) %> <% end %> </p> </div> <div class="pagination-content float-right"> <%= paginate(objects) %> </div> </div> </div> <% end %>
⚓ 6-2. Pagination Views
Run docker-compose exec app bin/rails g kaminari:views bootstrap4
, and required pagination views will be created.
<li class="page-item"> <%= link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, remote: remote, class: 'page-link' %> </li>
<li class="page-item disabled"> <%= link_to raw(t 'views.pagination.truncate'), '#', class: 'page-link' %> </li>
<li class="page-item"> <%= link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, remote: remote, class: 'page-link' %> </li>
<li class="page-item"> <%= link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, rel: 'next', remote: remote, class: 'page-link' %> </li>
<% if page.current? %> <li class="page-item active"> <%= content_tag :a, page, data: { remote: remote }, rel: page.rel, class: 'page-link' %> </li> <% else %> <li class="page-item"> <%= link_to page, url, remote: remote, rel: page.rel, class: 'page-link' %> </li> <% end %>
<%= paginator.render do %> <nav> <ul class="pagination"> <%= first_page_tag unless current_page.first? %> <%= prev_page_tag unless current_page.first? %> <% each_page do |page| %> <% if page.left_outer? || page.right_outer? || page.inside_window? %> <%= page_tag page %> <% elsif !page.was_truncated? %> <%= gap_tag %> <% end %> <% end %> <%= next_page_tag unless current_page.last? %> <%= last_page_tag unless current_page.last? %> </ul> </nav> <% end %>
<li class="page-item"> <%= link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, rel: 'prev', remote: remote, class: 'page-link' %> </li>
⚓ 6-3. Apply Pagination to Views
Render shared/pagination_header
to show the pagination header and call paginate method to show the pagination footer.
<h1>イベント一覧</h1> <%= render 'shared/pagination_header', objects: @events %> <div class="list-group"> <% @events.each do |event| %> <%= link_to(event, class: 'list-group-item list-group-item-action') do %> <h5 class="list-group-item-heading"><%= event.name %></h5> <p class="mb-1"><%= "#{l(event.start_at, format: :long)} - #{l(event.end_at, format: :long)}" %></p> <% end %> <% end %> </div> <div class="pagination-content float-right mt-4"> <%= paginate(@events) %> </div>
⚓ 7. Assets
Define styles for the pagination header and footer in /app/assets/stylesheets/pagination.css.scss
.
.pagination-field { display: table; width: 100%; margin-top: 10px; .pagination-wrapper { display: table-row; .entry-content { display: table-cell; width: 220px; vertical-align: middle; } .pagination-content { display: table-cell; vertical-align: middle; } } }