はじめに。
クラスメソッドやんわり理解し始めた人間が書いています。
”クラスメソッド 定義”とかで調べても、初心者には理解仕切れない部分があったので、「こんなこと書いてあれば理解の助けになったな」という内容を書いています。
タイトル通り、ページネーションの話から始まり、最後の方で少しクラスメソッドのこと書いてます。
##前提(環境)
ruby 2.6.3
rails 5.2.4
db PostgreSQL
gem kaminariを使用してページネーションをしています。
##やりたいこと
ページネーションを使用したページで、eachで繰り返し処理したものに、インデクス番号を付けたい。
##問題点
eachで繰り返し処理したものの番号を取得する場合、
each.with_index
の使用を考えると思います。
def index
@items = Item.page(params[:page]).per(10)
end
<% @items.each.with_index do |item,i| %>
<%= "#{i+1} 、 #{item.title}" %>
<% end %>
<%= paginate @items %>
これだと、ページ毎に番号を取得することとなり、常に1から数えてしまう。
##解決策
###クラス名.page(params[:page]).current
で、現在表示しているページが何ページ目かを表示できるため、
<% @items.each.with_index do |item,i| %>
<%= "#{(Item.page(params[:page]).current - 1)*10 + i + 1} 、 #{item.title}" %>
<% end %>
とすることで、
1ページ目であれば (1-1)*10+i+1 1〜10を表示
2ページ目であれば (2-1)*10+i+1 11〜20を表示
することができ、解決。
##リファクタリング
とても読みづらいコードなのでリファクタリング。
まず、インデックスを0から数える必要がないので
<% @items.each.with_index(1) do |item,i| %>
<%= "#{(Item.page(params[:page]).current - 1)*10 + i} 、 #{item.title}" %>
<% end %>
とできる。
更に長ったらし部分をコントローラーに出して
def index
@items = Item.page(params[:page]).per(10)
page_num = Item.page(params[:page]).current_page
@base_level = (page_num - 1)*10
end
<% @items.each.with_index(1) do |item,i| %>
<%= "@base_level + i} 、 #{item.title}" %>
<% end %>
とできる。
更に更に、クラスメソッドを定義して、コントローラーをすっきりと。
def index
@items = Item.page(params[:page]).per(10)
@base_level = Movie.base_level(params[:page])
end
class Item < ApplicationRecord
def self.base_level(page)
(self.page(page).current_page - 1) * 10
end
end
こんな感じできれい目に実装できるかと思います。
##備考(クラスメソッド のこと)
正直私はクラスメソッドの定義はかなり苦戦しました。
そもそもクラスメソッドって何?ってところからだったので。
その点はクラスメソッドでググるればいっぱい出てくると思うので、割愛しますが、私は
###params[:page]をクラスメソッドにどう受け渡すか
という点にハマったので少し解説します。
まずクラスメソッドにはparams使えません。
よって
class Item < ApplicationRecord
def self.base_level(page)
(self.page(params[:page]).current_page - 1) * 10
end
end
とは書けないのです。
ですがコントローラーで
Movie.base_level(params[:page])
とクラスメソッドで定義したbase_levelの引数に(params[:page])が入っています。
そしてクラスメソッドでは
def self.base_level(page)
と,引数は(page)になっています。
ですので
(params[:page])=(page)
の関係になっていると言えます。
よって今回は、"page(page)"となり、ファッ??って気持ちになるけど(・・・なりませんか?私はなりましたw)
class Item < ApplicationRecord
def self.base_level(page)
(self.page(page).current_page - 1) * 10
end
end
という記述になります。
それともう一つ、クラスメソッドはmodelに定義して下さいw
私ははじめ、コントローラーに定義しており、うんともすんとも動かないとうい時間を過ごしてしまいました。