kaminari 相關

kaminari是用來做分頁的gem,一開始聽到這個名字還有點意外外什麼是這個名字,因為kamianari(かみなり)在日文是閃電雷電的意思,所以拿來做為做分頁gem的名稱還蠻妙的。

Install

gem 'kaminari'
bundle insatll
rails s

Usage

基本的用法,預設的設定是每一頁顯示25筆資料。

controller

controller
def index
    @product = Product.all.page(4) #跳到第四頁

  #per是設定每一頁可以顯示幾筆資料,所以下面這行code就是

  #跳到第四頁,並且每一頁顯示一筆資料,所以假設總共有六筆資料

  #總共就有6個分頁,並且跳到第3頁,然後顯示一筆資料

  @product = Product.all.page(3).per(1) 
end
# << < 1 2 [3] 4 5 6 > >>

model

設定每頁幾筆資料的另一個方法是寫在model裡

model/product
class Product < ActiveRecord::Base
    paginates_per 2
end

然後在controller這樣寫,這樣的話kaminari就會根據 paginates_per 的設定自己去算總共需要幾個分頁,然後在view點擊分頁號碼的時候就會傳個paramters params[:page] 到controller 透過 page(params[:page]) 去跳到指定的分頁。

controller
def index
    @product = Product.all.page(params[:page])
end

view

資料設定好之後在view裡要加上分頁的地方加入ruby code就好了

<%= paginate @products%>

theme

想要客製化自己的分頁也可以,內建也theme可以用,這邊可以看 kaminari_themes

rails g kaminari:views bootstrap4

之後會在views建立一個kaminari資料夾,裡面有很多partial就可以自己改了

I18n

如果不喜歡他預設next prev的文字的話也可以建一個I18n yml檔修改

locals en.yml
en:
  views:
    pagination:
      first: "&laquo; First"
      last: "Last &raquo;"
      previous: "&lsaquo; Prev"
      next: "Next &rsaquo;"
      truncate: "&hellip;"

generate kaminari config file

想要更改預設設定的話可以建出config檔來設定

rails g kaminari:config

ajax

kaminari也可以用ajax的方式來顯示分頁內容

step1

加入remote:true 開啟ajax功能

<%= paginate @products , remote:true%>

step2

用RJS的方式加入分頁內容。

controller
  def index
    @products = Product.includes(:variants).page(params[:page])
    respond_to do |format|
      format.html
      format.js
    end
  end

step3

新增index.js.erb檔

index.js.erb
$("div#products").html("<%= j(render partial: 'your_partial', collection: @products, as: :product) %>");

//這邊比較要注意的點是kaminari分頁的部分也是要在render一次,不然分頁的號碼不會自己更新。

$("div.pagination-wrapper").html("<%= j(paginate( @products , remote: true).to_s) %>")

在redirect_to時如何更新分頁號碼

在有使用ajax kaminari分頁的頁面,用post將資料傳到後台後並且用redirect_to導回原本頁面的時候,會發現只能導到分頁的第一頁,所以下面要說說如何導回post前的所在頁面

下面是kaminari常用的api

@item.total_count #=> レコード総数 資料總比數

@item.offset_value #=> オフセット 分頁offset的比數

@item.num_pages #=> 総ページ数 總分頁

@item.per_page #=> 1ページごとのレコード数 每個分頁的資料筆數

@item.current_page #=> 現在のページ 現在的頁碼

@item.first_page? #=> 最初のページならtrue 是不是第一頁

@item.last_page? #=> 最後のページならtrue 是不是最後一頁

根據上面的api我們在post前可以連現在的頁碼一起post過去
在link_to路徑參數裡還可以加上額外的data,這邊我們給他加一個叫做page的資料 ,資料的內容拿經過kamanari處理過的instance variable來用,經過kamanari處理過的資料就可以用他的api,這邊我們就用current_page來取得現在得頁碼@products.current_page

view
<%= link_to "post data" , xxx_action_product_path(product , page:@products.current_page)%>
products_controller
def index
    @products = Product.all.page(params[:page])
    respond_to do |format|
      format.html
      format.js
    end
  end
def xxx_action
    ...(do somethiing)
  #params[:page] #=> "2"

  #這邊導回index頁面並且把page頁碼的參數帶回去給index action

  #這樣在index的地方就可以抓到現在頁碼並且停在該頁

    redirect_to products_path(page:params[:page])
end

之後就可以成功導回post前的所在頁面。
但這邊其實還有個小問題是導回原本頁面後會發現網址出現了paramter像是這樣http://localhost:3000/products?page=2,然後再切換分頁時雖然功能是正常運作,出來的資料也是正確,但網址始終還是不變一樣是
http://localhost:3000/products?page=2,這邊就需要用一個小技巧把網址後面的paramter拿掉,並且不要reload頁面,因為如果reload的話就失去ajax的意義囉
可以在index.js.erb的最後一行加上

window.history.pushState('', document.title, window.location.href.split("?")[0]);

這樣之後再切分頁的時候網址上的paramter就會不見了,就不會發生明明是切到別頁可是url的paramter還是停留在page=2

另外切換分頁時還有可能會遇到js不會執行的情況,如果是用一般get的方式做分頁的話可以把

- $(document).ready(function(){
- });
#換成
+ $(document).on("page:change" , function(){
+ });

如果是用ajax方式做分頁的情況的話,就把要做的事情包成一個function,然後在js.erb裡再呼叫這個function一次就可以了。

comments powered by Disqus