6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Rails】グループ化した際のページネーション

Posted at

はじめに

レコードの一覧をグループ化して表示する際のページネーションについて、少し躓いたのでまとめます。
ページネーションはkaminariを使用しています。

普段のページネーション

例えば、全てのユーザーを取得して10件ずつ一覧に表示するようなページネーションは以下のようになります。

app/controllers/users_controller.rb
def index
  page = params[:page] || 1
  @users = User.all.page(page).per(10)
end
app/views/users/index.html.erb
<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では配列に対してもページネーションをさせることができます。

app/controllers/users_controller.rb
  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
app/views/users/index.html.erb
<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カラムの値ごとにグループ化して一覧を表示させたい場面があります。

さらにこの画面の中でユーザーに対してページネーションをするための実装を想定します。

スクリーンショット 2020-07-16 0.41.09.png
app/controllers/users_controller.rb
def index
  # 全てのユーザーを取得し、countryカラムの文字コード順に並べ替える
  users = User.all.order(country: "DESC").order(id: "ASC")
  @users_hash = users.gruop_by {|user| user.country}
end

app/views/users/index.html.erb
<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を使用すると、

ブロックを評価した結果をキー、対応する要素の配列を値とするハッシュを返すことができます。

railsリファレンスマニュアル

先ほど配列に対してページネーションをした際には、配列の中に各ユーザーごとのデータが格納されたハッシュを入れていました。
なので、users.lengthKaminari.paginate_array(array).lengthの結果が一致します。(1ページあたりの項目数はデフォルトだと25なので、users.length < 25の場合)

しかし、今回の場合ハッシュのkey,valueを配列の値としてpaginate_arrayに入れると[{key1, [value1, value2]},{key2,[value3, value4, value5]}...]のようになり、ハッシュのkeyと同様の数(配列の要素数)に対してページネーションがされることになります。

つまり、

pp/controllers/users_controller.rb
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項目以上の場合にページネーションをさせたいので、欲しい出力は得られなません。

解決策

以下のように実装することで解決できました。

app/controllers/users_controller.rb
 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
app/views/users/index.html.erb
<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>

上記の出力は次のようになり、目標としていた出力が得られました!

1ページ目
スクリーンショット 2020-07-16 0.26.44.png

2ページ目
スクリーンショット 2020-07-16 0.26.53.png

参考

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?