Phân trang trong Rails sử dụng Gem Kaminari và tạo select limit load với gem Ransack

1.Giới thiệu

Phân trang là một kĩ thuật rất phổ biến và quan trọng trong các trang web lớn,khi mà số lượng các item nhiều. Đó là yếu tố sống còn của website khi mà nó trực tiếp ảnh hưởng đến hiệu năng của hệ thống. Tôi lấy một ví dụ đơn gian nếu chúng ta cần phải load ra 100000 bản ghi tốn mất khoảng 3s thì với 1 triệu bản ghi sẽ mất khoảng 30s. Điều đó là không thể chấp nhận được khi bắt người dùng chờ đến 30s/1 request.Hơn nữa việc load ra tất cả các bản ghi 1 lúc là không cần thiết khi mà người dùng không thể xem hết một lúc 1 triệu bản ghi được. Hôm nay tôi sẽ hướng dẫn các bạn sử dụng gem kaminari trong Rails để phân trang cho list item của bạn. Cộng với một phần ứng dụng Gem tìm kiếm Ransack để tạo form slect số lượng item bạn muốn load trên một trang.

Chém gio thế chắc cũng đủ rồi.Chúng ta bắt đầu nào!

2.Các bước thực hiện

2.1. Khởi tạo một project mới với Rails và thêm các Gem cần thiết vào


rails new kaminari_demo

Trong file Gemfile chúng ta thêm các Gem sau


gem 'kaminari'       // gíup phân trang
gem 'ransack'     // tạo form tìm kiếm
gem 'bootstrap-kaminari-views' // giao diện đẹp cho phân trang

2.2. Tạo một trang Product, tạo cơ sở dữ liệu mẫu và viết view + controller

Tạo model Product


rails generate model Product

viết view và controller

Tạo file app/controllers/products_controller.rb

class ProductsController < ApplicationController

  def index
    @products = Product.all
  end
end

Trong file app/views/product.html.erb

<h1>ALL PRODUCT</h1>
<%- @products.each do |product| %>
  <%= product.title %>
  </br>
<% end %>

Trong file config/routes.rb

Rails.application.routes.draw do
  resources :products
end

Fake dữ liệu nữa chúng ta sẽ được một trang Products như thế này

1.png

2.3. Phân trang

Chúng ta viết trong file app/controllers/products_controller.rb

  def index
    @products = Product.all.page params[:page]
  end

Trong file app/views/product.html.erb

<%- @products.each do |product| %>
  <%= product.title %>
  </br>
<% end %>
<%= paginate @products %>

Chúng ta sẽ thu được một trang Product đã được phân trang như sau.

2.png

Như vậy là chúng ta đã tạo thành công một trang products sử dụng Gem kaminari để phân trang.

2.4 Config Gem Kaminari và chỉnh giao diện

  • Giới hạn số lượng Item

Chúng ta có thể giới hạn số lượng item load ra trên một trang như sau.trong file app/controllers/products_controller.rb

  def index
    @products = Product.all.page(params[:page]).per(5)
  end

chúng ta sẽ thu được như sau. 3.png

  • Config các thông số khác

Ngoài ra chúng ta có thể generate ra file config bằng lệnh

% rails g kaminari:config

Sẽ tạo ra file config/initializers/kaminari_config.rb

Kaminari.configure do |config|
  # config.default_per_page = 25
  # config.max_per_page = nil
  # config.window = 4
  # config.outer_window = 0
  # config.left = 0
  # config.right = 0
  # config.page_method_name = :page
  # config.param_name = :page
end
  • Chỉnh lại giao diện đẹp

Để chỉnh lại giao diện đẹp mắt trước tiên chúng ta phải cài Gem bootstrap.Các bạn có thể xam hướng dẫn cài đặt bootstrap tại đây

Trong file app/views/product.html.erb chúng ta thêm theme: 'twitter-bootstrap-3'

<%- @products.each do |product| %>
  <%= product.title %>
  </br>
<% end %>
<%= paginate @products, theme: 'twitter-bootstrap-3' %>

chúng ta sẽ thu được như hình dưới đây.

4.png

  • Chỉnh I18n và lable

Kaminari mặc định các I18n và các lable là 'first', 'last', 'previous', '…' and 'next',chúng ta có thể thay đổi các lable này bằng cách override trong file config/locales/en.yml như sau:

en:
  hello: "Hello world"
  views:
    pagination:
      first: "« FIRST"
      last: "LAST »"
      previous: "‹ PREV"
      next: "NEXT ›"
      truncate: "…"
  helpers:
    page_entries_info:
      one_page:
        display_entries:
          zero: "No %{entry_name} found"
          one: "Displaying <b>1</b> %{entry_name}"
          other: "Displaying <b>all %{count}</b> %{entry_name}"
      more_pages:
        display_entries: "Displaying %{entry_name} <b>%{first} - %{last}</b> of <b>%{total}</b> in total"

chúng ta sẽ thu được giao diện mới như sau:

5.png

Bạn thấy các lable đã được viết hoa.

  • Tạo friendly URLs

Để tạo một đường dẫn thân thiện giúp cho SEO dễ dàng hơn.chúng ta có thể chỉnh trong file config/routes.rb như sau:

Rails.application.routes.draw do
  concern :paginatable do
    get '(page/:page)', action: :index, on: :collection, as: ''
  end

  resources :products, concerns: :paginatable
end

Sẽ tạo thành URLs /products/page/3 instead of /products?page=3

6.png

3.Select limit item với Gem ransack

Để tạo được một select form trước tiên chúng ta add thêm gem ransack và gem config vào Gemfile

gem 'ransack'
gme 'config'

Trong file config/settings.yml thêm các lựa chọn vào các settings như sau:

show_limit:
  show_5: 5
  show_10: 10
  show_15: 15
  show_20: 20
  show_30: 30
  show_50: 50

Truyền biến @search từ trong controller ra ngoài view.Ở đây chúng ta phải nhận params[:limit] từ ngoài view truyền vào.

def index
    @search = Product.all.ransack params[:q]
    @products = @search.result.page(params[:page]).per params[:limit]
end

Sau đó tạo một form search trong html.Đây là form search sử dụng gem ransack. Chúng ta sẽ để ẩn nút submit đi. Chi tiết về gem ransack bạn có thể xem tại đây

<%= search_form_for @search, url: products_path do |f|%>
  <%= select_tag :limit, options_from_collection_for_select(Settings.show_limit, :second, :second, selected: params[:limit] || Settings.show_limit.limit),id: "show-limit"%>
  <%= f.submit "search", class: "btn btn-info", style: "display: none; margin-right: 10px"%>
<% end %>

Cuối cùng bạn cần phải viết một đoạn javascript để nhấn nút submit mỗi khi select changed.bạn có thể viết ngay trong app/assets/javascripts/application.js

$(function(){
  $("#show-limit").on("change", function(){
    $(this).closest("form").trigger("submit");
  });
})

Đến đây chúng ta sẽ thu được một form select limit load như thế này. 7.png

8.png

Bạn chọn 20 và form sẽ load ra 20 products. Như vậy là tôi đã hướng dẫn xong toàn bộ cách phân trang cho trang web trong Rails sử dụng Gem Kaminari và tạo select limit load với gem Ransack.Chúc các bạn thực hiện thành công và có những ứng dụng hay vào trong trang web của mình!

4.Tài liệu tham khảo

https://github.com/railsconfig/config https://github.com/activerecord-hackery/ransack https://github.com/amatsuda/kaminari

Tất cả source code của project demo các bạn có thể lấy về ở đây

-- Hoàng Văn Trình AS Việt Nhật K55 Đại học Bách Khoa Hà Nội