一覧表示画面にページネーション機能をつけた際に勉強になった事を備忘録として残しています。
前提
ページネーション機能をつける前のビューなどです。
コントローラー
事前にソート機能をつけています。
class StocksController < ApplicationController
helper_method :sort_column, :sort_direction
def index
@calendar = Calendar.find(params[:calendar_id])
@stocks = @calendar.stocks.order("#{sort_column} #{sort_direction}")
@products = Product.all
end
private
def sort_direction
%w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc'
end
def sort_column
Stock.column_names.include?(params[:sort]) ? params[:sort] : 'id'
end
end
ヘルパーメソッド(追記)
大事なヘルパーメソッドの記述を抜かっておりました・・・。
module StocksHelper
def sort_order(column, title)
css_class = (column == sort_column) ? "current #{sort_direction}" : nil
direction = (column == sort_column && sort_direction == 'asc') ? 'desc' : 'asc'
link_to title, { sort: column, direction: direction }, class: "sort_header #{css_class}"
end
end
ビュー
<table>
<thead>
<tr>
<th scope="col"><%= sort_order "display", "陳列" %></th>
<th scope="col"><%= sort_order "publisher", "出版社名" %></th>
<th scope="col"><%= sort_order "magazine_name", "雑誌名" %></th>
<th scope="col"><%= sort_order "num", "冊数" %></th>
<th scope="col"><%= sort_order "price", "本体価格" %></th>
<th scope="col"><%= sort_order "i_form", "発行形態" %></th>
<th scope="col"><%= sort_order "purchased", "買切雑誌" %></th>
</tr>
</thead>
<tbody>
<% @stocks.each do |stock| %>
<% if stock.num > 0 %>
<tr>
<td><%= stock.display %></td>
<td><%= stock.publisher %></td>
<td><%= stock.magazine_name %></td>
<td><%= stock.num %></td>
<td><%= stock.price.to_s(:delimited) %></td>
<td><%= stock.i_form %></td>
<td><%= stock.purchased %></td>
</tr>
<% end %>
<% end %>
</tbody>
</table>
ページネーションの実装
今回kaminariというページネーション用のgemを使って実装しました。
意外と簡単に実装できました〜。
kaminariのインストール
Gemfileにgem 'kaminari'
を追加し、$ bundle install
でインストールします。
gem 'kaminari'
gemをインストールした後は一度サーバを再起動しましょう。
Ctrl-c
でサーバを止め、 rails s
でサーバを起動できます。
また、忘れてて右往左往しました・・・。
これでkaminariのインストールは完了です。
ページネーションを表示させる
お次はcontrollerです。
ページネーションを表示させたいデータに.page(params[:page])
を追加します。
def index
# ページネーションをつけたいデータに.page(params[:page])を追加
@stocks = @calendar.stocks.page(params[:page]).order("#{sort_column} #{sort_direction}")
end
余談(1.ページに表示するレコード数の変更)
1ページに表示するレコード数は初期値では25件なのだそうです。
controllerに.per(表示したいレコード数)
を追加すると変更できるそうです。
例えば、30件表示したい場合は.per(30)
と追加。
def index
# .per(30)を追加
@stocks = @calendar.stocks.page(params[:page]).per(30).order("#{sort_column} #{sort_direction}")
end
って感じです。
最後に、viewでページネーションを表示させたいところへ
<%= paginate @stocks %>
を追加します。
<%= paginate @stocks %>
<table>
〜〜 省略 〜〜
</table>
余談(2.表示を日本語に変更する)
ページ番号の前後についている<<First
とか<Prve
は判りづらいと感じたので
こちらを日本語に変更していきます。
# 〜〜省略〜〜
module Teiki29770(アプリ名です)
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 6.0
# 日本語の言語設定
config.i18n.default_locale = :ja
config.time_zone = 'Tokyo'
# Settings in config/environments/* take precedence over those specified here.
# Application configuration can go into files in config/initializers
# -- all .rb files in that directory are automatically loaded after loading
# the framework and any gems in your application.
end
end
サーバを再起動しましょう!
config/locales
に日本語変換用のymlファイルja.yml
を作成して、
以下のコードを追加してみます。
ja:
views:
pagination:
first: "« 最初"
last: "最後 »"
previous: "‹ 前"
next: "次 ›"
truncate: "..."
これで表示を日本語に変更できました!やった!!
と、思っていたら・・・。
表示数にズレが出てしまう。
なんか少ない・・・。30件表示できるはずなのに・・・。
調べてみると他のページも表示数はまちまちでした。
ビューでの条件式が原因
コントローラーで指定している通り、30件づつデータを送って
ビューのほうで条件式に合うデータのみを表示していることが原因でした。
〜〜 省略 〜〜
<tbody>
<% @stocks.each do |stock| %>
<% if stock.num > 0 %>⇦ここが原因。
<tr>
<td><%= stock.display %></td>
<td><%= stock.publisher %></td>
<td><%= stock.magazine_name %></td>
<td><%= stock.num %></td>
<td><%= stock.price.to_s(:delimited) %></td>
<td><%= stock.i_form %></td>
<td><%= stock.purchased %></td>
</tr>
<% end %>
<% end %>
</tbody>
</table>
なので、コントローラーの方で条件に合うデータだけを先に抽出しておいて
そちらを30件ずつビューへ送る様にします。
def index
@calendar = Calendar.find(params[:calendar_id])
@stocks = @calendar.stocks.where("num > ?",0).page(params[:page]).per(30).order("#{sort_column} #{sort_direction}")
end
〜〜 省略 〜〜
<tbody>
<% @stocks.each do |stock| %>
〜〜 if文を削除 〜〜
<tr>
<td><%= stock.display %></td>
<td><%= stock.publisher %></td>
<td><%= stock.magazine_name %></td>
<td><%= stock.num %></td>
<td><%= stock.price.to_s(:delimited) %></td>
<td><%= stock.i_form %></td>
<td><%= stock.purchased %></td>
</tr>
<% end %>
</tbody>
</table>
これで、しっかりと条件に沿ったデータを表示することができました!
ちゃんとソートもできます!
勉強になったこと
MVCの関係性の大事さと共に、役割分担をしっかりとすることの大切さを再確認できました。
ありがとう、ページネーション!
参考にさせていただいたサイト様
https://qiita.com/rio_threehouse/items/313824b90a31268b0074
ありがとうございます!