Trong bài này chúng ta sẽ thực hiện chức năng phân trang.
Trong Rails không có hàm hay lớp nào có thể thực hiện chức năng phân trang được. Tuy nhiên do Rails là mã nguồn mở nên cũng có cộng đồng hỗ trợ rất lớn, rất nhiều thư viện được viết ra để hỗ trợ chúng ta. Các thư viện hỗ trợ phân trang cũng rất nhiều, ở đây chúng ta sẽ sử dụng thư viện will_paginate,
có địa chỉ github tại https://github.com/mislav/will_paginate.
Chúng ta không cần phải tự tải về rồi biên dịch gì hết. Mặc định Rails có phần mềm quản lý các thư viện này rồi, đó là phần mềm Gem. Chúng ta sẽ tìm hiểu cách sử dụng gem sau.
Cài đặt will_paginate
Đầu tiên chúng ta khai báo thư viện này trong file Gemfile
, file này không có phần mở rộng và nằm ở thư mục gốc của project:
source 'http://rubygems.org' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '4.2.5.1' # Use sqlite3 as the database for Active Record gem 'sqlite3' # Use SCSS for stylesheets gem 'sass-rails', '~> 5.0' # Use Uglifier as compressor for JavaScript assets gem 'uglifier', '>= 1.3.0' # Use CoffeeScript for .coffee assets and views gem 'coffee-rails', '~> 4.1.0' # See https://github.com/rails/execjs#readme for more supported runtimes # gem 'therubyracer', platforms: :ruby # Use jquery as the JavaScript library gem 'jquery-rails' # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks gem 'turbolinks' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder gem 'jbuilder', '~> 2.0' # bundle exec rake doc:rails generates the API under doc/api. gem 'sdoc', '~> 0.4.0', group: :doc # Use ActiveModel has_secure_password # gem 'bcrypt', '~> 3.1.7' # Use Unicorn as the app server # gem 'unicorn' # Use Capistrano for deployment # gem 'capistrano-rails', group: :development group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug' end group :development do # Access an IRB console on exception pages or by using <%= console %> in views gem 'web-console', '~> 2.0' end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] gem 'will_paginate', '>= 3.0'
Phiên bản mới nhất được phát hành vào tháng 10/2016 là phiên bản 3.1.5. Chúng ta khai báo dòng gem 'will_paginate', '>= 3.0'
cho biết chúng ta muốn dùng phiên bản 3.0 trở đi, nhưng không dùng 4.0.
Tiếp theo chúng ta cài thư viện này bằng lệnh bundle install
:
C:\Projects\Rails\depot>bundle install ... Installing will_paginate 3.1.5 ...
Vậy là xong, bạn có thể sẽ cần phải khởi động lại server nếu có đang chạy.
Tạo dữ liệu mẫu
Chúng ta tạo 100 bản ghi Order
để làm dữ liệu test. Thay vì tự ngồi gõ từng form đặt hàng thì chúng ta có thể chạy đoạn code có sẵn.
Chúng ta tạo một file có tên create_dummy_orders.rb
nằm trong thư mục bin
có nội dung như sau:
Order.transaction do (1..100).each do |i| Order.create(:name => "Customer #{i}", :address => "#{i} Street", :email => "customer_#{i}@phocode.com", :pay_type => "Bank Card") end end
Đoạn code trên sẽ tạo 100 bản ghi Order
. Để chạy đoạn code này thì chúng ta chạy lệnh rails runner bin/create_dummy_orders.rb
:
C:\Projects\Rails\depot>rails runner bin/create_dummy_orders.rb
Lưu ý là đây không phải dữ liệu seed như chúng ta đã từng làm.
Bây giờ bạn có thể vào trang /orders
và thấy danh sách 100 đơn hàng được hiển thị đầy đủ.
Phân trang
Chúng ta sẽ phân trang để cho hiển thị 10 đơn hàng trên một trang, đầu tiên chúng ta sửa lại phương thức index
trong lớp OrdersController
như sau:
class OrdersController < ApplicationController . . . # GET /orders # GET /orders.json def index @orders = Order.paginate(:page => params[:page], :per_page => 10).order('created_at desc') end . . . end
Thư viện will_paginate
cho phép chúng ta sử dụng một phương thức có tên là paginate
trên các đối tượng lưu trữ theo dạng danh sách. Phương thức này nhận vào tham số trang, ở đây là :page,
tức là khi chúng ta xem các trang thì URL sẽ có dạng /orders?page=1, /orders?page=2
… đây là tham số mặc định do thư viện này quy định. Phương thức này còn nhận vào tham số :per_page
là số lượng “item” được hiển thị trên mỗi trang.
Ngoài ra chúng ta có thể sắp xếp các phần tử này bằng phương thức order,
phương thức này nhận vào một chuỗi có dạng "<tên_trường> asc|desc",
và các phần tử sẽ được sắp xếp dựa theo tên trường, ASC là sắp xếp từ A-Z, DESC thì ngược lại. Ở đây chúng ta sắp xếp theo trường created_at
với thứ tự là DESC.
Cuối cùng trong file View app/views/orders/index.html.erb
chúng ta sửa lại như sau:
<p id="notice"><%= notice %></p> <h1>Listing Orders</h1> <table> <thead> <tr> <th>Name</th> <th>Address</th> <th>Email</th> <th>Pay type</th> <th colspan="3"></th> </tr> </thead> <tbody> <% @orders.each do |order| %> <tr> <td><%= order.name %></td> <td><%= order.address %></td> <td><%= order.email %></td> <td><%= order.pay_type %></td> <td><%= link_to 'Show', order %></td> <td><%= link_to 'Edit', edit_order_path(order) %></td> <td><%= link_to 'Destroy', order, method: :delete, data: { confirm: 'Are you sure?' } %></td> </tr> <% end %> </tbody> </table> <br> <%= link_to 'New Order', new_order_path %> <p><%= will_paginate @orders %></p>
Chúng ta gọi hàm helper là will_paginate
với tham số là @orders
để tạo các thẻ <a>
dẫn tới từng trang cụ thể.
Vậy là xong, bây giờ trang /orders
sẽ hiển thị như thế này: