Sinatora で kaminari を使ってページネーションの機能を追加する - Sinatra

Kaminari とは?

Kaminari はページネーションの機能を追加する gem になります。

Sinatra ヘルパーなどの gem をインストールしてもページネーションのリンクがなぜか表示されなかったため、ページネーションのリンクは自分で作成しています。

Sinatra で利用するために以下の gem を追加します。

  • 'mysql2'
  • 'activerecord'
  • 'sinatra-activerecord'(2.0.28)
  • 'kaminari'(1.2.2)

上記の gem を Gemfile に追加したら bundle install します。

bundle install --path vendor/bundle

Sinatra アプリのフォルダ構成は以下のようにします。

ディレクトリ構成

  • Project
    • .bundle
    • config
      • initializers
        • kaminari.rb
    • db
        database.yml
    • views
      • share
        • _pagenation.erb
      • member.erb
    • app.rb
    • config.ru
    • Gemfile
    • Gemfile.lock

Kaminari の設定ファイルを分ける

「 config/initializers/kaminari.rb 」というディレクトリとファイルを作成します。ファイルの中を以下のようにします。

config/initializers/kaminari.rb

Kaminari.configure do |config|
  config.default_per_page = 2
  config.max_per_page = 100
  config.window = 4
  config.outer_window = 0
  config.left = 2
  config.right = 2
  config.page_method_name = :page
  config.param_name = :page
end

default_per_page

1ページあたりの表示する件数(デフォルトは25レコード)

max_per_page

1ページあたりの最大表示件数(デフォルトはnil。つまり無限)

max_pages

最大ページ数(デフォルトはnil)

window

現在のページから、何ページ分のリンクを左右に表示させるか(デフォルトは4件)

outer_window

最初と最後のページから、何ページ分のリンクを左右に表示させるか(デフォルトは0件)

left

最初のページから、何ページ分のリンクを表示させるか(デフォルトは0件)

right

最終ページから、何ページ分のリンクを表示させるか(デフォルトは0件)

page_method_name

モデルに追加されるページ番号を指定するスコープの名前(デフォルトは:page)

param_name

ページ番号を渡すために使用するパラメータ名(デフォルトは:page)

ファイルの内容

app.rb

require "sinatra"
require 'sinatra/activerecord'
require 'kaminari'
require_relative 'config/initializers/kaminari'

ActiveRecord::Base.configurations = YAML.load_file('./db/database.yml')
ActiveRecord::Base.establish_connection(:development)

class Member < ActiveRecord::Base
end

class SampleApp < Sinatra::Base
  get '/members/:page' do
    @members = Member.page(params[:page])
    erb :members
  end
end

kaminari の初期設定を変更するには、以下のファイルを作り設定します。また、app.rb のファイル内に直接記述しても構いません。

config/initializers/kaminari.rb

Kaminari.configure do |config|
  config.default_per_page = 10
  config.max_per_page = 100
  config.window = 4
  config.outer_window = 0
  config.left = 2
  config.right = 2
  config.page_method_name = :page
  config.param_name = :page
end

members.erb

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Member List</title>
</head>
<body>
  <h1>Member List</h1>
  <p>ページ総数:<%= @members.total_pages %></p>
  <p>現在のページ:<%= @members.current_page %></p>
  <p>
    <% if @members.prev_page %>
      <a href="/members/<%= @members.prev_page %>">Prev</a>
    <% end %>
    <% if @members.next_page %>
      <a href="/members/<%= @members.next_page %>">Next</a>
    <% end %>
  </p>
  <ul>
    <% @members.each do |member| %>
      <li>(id:<%= member.id.to_s %>):<%= member.name %> (<%= member.age.to_s %>)</li>
    <% end %>
  </ul>

  <%= erb :"share/_pagination" %>
</body>
</html>

ページネーションのリンクを部分テンプレートで作成するには以下のようにします。

share/_pagination.erb

<% if @members.total_pages > 1 %>
  <div class="pagination">
    <% if @members.prev_page %>
      <a href="/members/<%= @members.prev_page %>">Prev</a>
    <% end %>

    <% (1..@members.total_pages).each do |page| %>
      <% if @members.current_page == page %>
        <span><%= page %></span>
      <% else %>
        <a href="/members/<%= page %>"><%= page %></a>
      <% end %>
    <% end %>

    <% if @members.next_page %>
      <a href="/members/<%= @members.next_page %>">Next</a>
    <% end %>

    <% if @members.next_page %>
      <a href="/members/<%= @members.total_pages %>">最後</a>
    <% end %>
  </div>
<% end %>

ブラウザで以下のアドレスを入力し、画面が表示されれば成功です。

http://127.0.0.1:9292/member/1

ページネーションリンク変更

表示するリンクの数を指定できるように変更するには以下のようにします。

share/_pagenation.erb

<%= link_length = 10 %>

<% if @members.total_pages > 1 && @members.total_pages <= link_length %>
  <div class="pagination">
    <% if @members.prev_page %>
      <a href="/members/1">最初</a>
    <% end %>

    <% if @members.prev_page %>
      <a href="/members/<%= @members.prev_page %>">Prev</a>
    <% end %>

    <% (1..@members.total_pages).each do |page| %>
      <% if @members.current_page == page %>
        <span><%= page %></span>
      <% else %>
        <a href="/members/<%= page %>"><%= page %></a>
      <% end %>
    <% end %>

    <% if @members.next_page %>
      <a href="/members/<%= @members.next_page %>">Next</a>
    <% end %>

    <% if @members.next_page %>
      <a href="/members/<%= @members.total_pages %>">最後</a>
    <% end %>
  </div>
<% end %>

<% if @members.total_pages > link_length %>
  <div class="pagination">
    <% if @members.prev_page %>
      <a href="/members/1">最初</a>
    <% end %>

    <% if @members.prev_page %>
      <a href="/members/<%= @members.prev_page %>">Prev</a>
    <% end %>

    <% if(@members.current_page == 1) %>
      <% ( 1..@members.current_page + (link_length - 1)).each do |page| %>
        <% if @members.current_page == page %>
          <span><%= page %></span>
        <% else %>
          <a href="/members/<%= page %>"><%= page %></a>
        <% end %>
      <% end %>

    <% elsif (@members.current_page > 1 &&  @members.current_page <= (@members.total_pages - link_length)) %>
      <% ( @members.current_page..@members.current_page + (link_length - 1)).each do |page| %>
        <% if @members.current_page == page %>
          <span><%= page %></span>
        <% else %>
          <a href="/members/<%= page %>"><%= page %></a>
        <% end %>
      <% end %>

    <% elsif ( (@members.current_page) > (@members.total_pages - link_length)) %>
      <% ( (@members.total_pages - link_length + 1)..(@members.total_pages)).each do |page| %>
        <% if @members.current_page == page %>
          <span><%= page %></span>
        <% else %>
          <a href="/members/<%= page %>"><%= page %></a>
        <% end %>
      <% end %>
    <% end %>

    <% if @members.next_page %>
      <a href="/members/<%= @members.next_page %>">Next</a>
    <% end %>

    <% if @members.next_page %>
      <a href="/members/<%= @members.total_pages %>">最後</a>
    <% end %>
  </div>
<% end %>