はじめに
レコードの一覧をグループ化して表示する際のページネーションについて、少し躓いたのでまとめます。
ページネーションはkaminariを使用しています。
普段のページネーション
例えば、全てのユーザーを取得して10件ずつ一覧に表示するようなページネーションは以下のようになります。
def index
  page = params[:page] || 1
  @users = User.all.page(page).per(10)
end
<table>
  <thead>
    <tr>
      <th>ユーザー情報</th>
    </tr>
  </thead>
  <tbody>
  <% @users.each do |user| %>
    <tr>
      <td>id:<%= user.id %></td>
      <td>name:<%= user.name %></td>
    </tr>
  </tbody>
  <% end %>
</table>
<div class="m_t_30">
  <ul><%= paginate(@users) %></ul>
</div> 
また、kaminariでは配列に対してもページネーションをさせることができます。
  def index
    page = params[:page] || 1
    array = []
    users = User.all
    users.each do |user|
      array.push({
        id: user.id,
        name: user.name
      })
    end
    @paginated_array = Kaminari.paginate_array(array).page(params[:page]).per(10)
  end
<table>
  <thead>
    <tr>
      <th>ユーザー情報</th>
    </tr>
  </thead>
  <tbody>
  <% @paginated_array.each do |item| %>
    <tr>
      <td>id:<%= item[:id] %></td>
      <td>name:<%= item[:name] %></td>
    </tr>
  </tbody>
  <% end %>
</table>
<div class="m_t_30">
  <ul><%= paginate(@paginated_array) %></ul>
</div> 
つまずいた場面
レコードをグループ化して表示させたい場面でのページネーションをどう実装するかで迷いました。
例
例えば以下のように、ユーザーを一覧に表示する際に、各ユーザーの持つcountryカラムの値ごとにグループ化して一覧を表示させたい場面があります。
さらにこの画面の中でユーザーに対してページネーションをするための実装を想定します。
 
def index
  # 全てのユーザーを取得し、countryカラムの文字コード順に並べ替える
  users = User.all.order(country: "DESC").order(id: "ASC")
  @users_hash = users.gruop_by {|user| user.country}
end
<table>
  <thead>
    <tr>
      <th>国別一覧</th>
    </tr>
  </thead>
  <tbody>
    <% @users_hash.keys.each do |country| %>
      <% users = @users_hash[country] %>
        <tr>
          <th><%= country %>グループ</th>
        </tr>
        <% users.each do |user| %>
        <tr>
          <td><%= user.name %></td>
        </tr>
      <% end %>
    <% end %>
  </tbody>
</table>
グループ化するためにはgroup_byを使用します。
gruop_byを使用すると、
ブロックを評価した結果をキー、対応する要素の配列を値とするハッシュを返すことができます。
先ほど配列に対してページネーションをした際には、配列の中に各ユーザーごとのデータが格納されたハッシュを入れていました。
なので、users.lengthとKaminari.paginate_array(array).lengthの結果が一致します。(1ページあたりの項目数はデフォルトだと25なので、users.length < 25の場合)
しかし、今回の場合ハッシュのkey,valueを配列の値としてpaginate_arrayに入れると[{key1, [value1, value2]},{key2,[value3, value4, value5]}...]のようになり、ハッシュのkeyと同様の数(配列の要素数)に対してページネーションがされることになります。
つまり、
def index
~~
略
array = [{key1, [value1, value2]},{key2,[value3, value4, value5]}...]
@paginated_array = Kaminari.paginate_array(array).page(params[:page]).per(10)
とすると、keyが10項目以上にならなければページネーションされないことになります。
今回のケースではvalueが10項目以上の場合にページネーションをさせたいので、欲しい出力は得られなません。
解決策
以下のように実装することで解決できました。
 def index
    page = params[:page] || 1
    @users = User.all.order(country: "DESC").order(id: "ASC").page(page).per(15)
    @users_hash = @users.group_by {|user| user.country}
  end
<table>
  <thead>
    <tr>
      <th>国別一覧</th>
    </tr>
  </thead>
  <tbody>
    <% @users_hash.keys.each do |country| %>
      <% users = @users_hash[country] %>
        <tr>
          <th><%= country %>グループ</th>
        </tr>
        <% users.each do |user| %>
        <tr>
          <td><%= user.name %></td>
        </tr>
      <% end %>
    <% end %>
  </tbody>
</table>
<div class="m_t_30">
  <ul><%= paginate(@users) %></ul>
</div>
上記の出力は次のようになり、目標としていた出力が得られました!

