บ่อยครั้งที่ view ของแอพพลิเคชั่นคุณต้องแสดงแค่ข้อมูลบางส่วนจากทั้งหมด ในกรณีนี้คุณต้องใช้เทคนิคการแบ่งหน้า (pagination) ซึ่งสามารถทำได้ไม่ยากโดยใช้ gem WillPaginate
หมายเหตุ: คุณต้องใช้ Ruby gems เวอร์ชั่น 1.2 ขึ้นไปเพื่อใช้งาน WillPaginate
(เนื้อหาส่วนใหญ่ในหน้านี้มาจาก เอกสารอ้างอิงของ WillPaginate)
WillPaginate gem ถูกสร้างโดย GitHub เพราะฉะนั้นคุณต้องเพิ่ม GitHub เป็นหนึ่งในแหล่งที่มาของ gem ของคุณ:
$ gem sources -a http://gems.github.com
ติดตั้งไลบรารี่:
$ gem install mislav-will_paginate
เริ่มใช้งานไลบรารี่นี้ได้ง่ายๆโดยโหลดมันขึ้นมาใน “config/environment.rb”
Rails::Initializer.run do |config| ... end require "will_paginate"
อย่าเพิ่มบรรทัด require ก่อนหรือภายในบล๊อก Rails::Initializer เพราะว่า Rails ยังไม่ถูกโหลดขึ้นมาในส่วนดังกล่าว
สำหรับ Rails เวอร์ชั่น 2.1 ขึ้นไปเราแนะนำให้คุณใช้ Gem dependencies เพื่อโหลด will_paginate โดยเพิ่มโค้ดนี้เข้าไปในไฟล์ config/environment.rb:
Rails::Initializer.run do |config| ... config.gem 'mislav-will_paginate', :lib => 'will_paginate', :source => 'http://gems.github.com' ... end
ใช้ paginate finder ใน controller:
page = params[:page] || 1 @posts = Post.paginate_by_board_id @board.id, :page => page, :order => 'updated_at DESC'
Paginate ทำงานเหมือนกับ find — จะต่างกันก็ตรงที่มันไม่คืนทุก record มาให้คุณ เพราะฉะนั้นอย่าลืมบอกว่าคุณต้องการข้อมูลหน้าไหน ไม่งั้นคุณจะเจอปัญหาได้! ลองอ่านข้อมูลเพิ่มเติมที่หน้า WillPaginate::Finder::ClassMethods
สำหรับการเรนเดอร์ข้อมูล คุณสามารถทำได้ตามปกติ ถ้าคุณต้องการเรนเดอร์ข้อมูลแบบเป็นหน้าๆให้ใช้โค้ดแบบนี้:
<%= will_paginate @posts %>
Will_paginate จะคำนวนว่าต้องแสดงกี่ record ในแต่ละหน้าโดยเรียกใช้ method per_page สำหรับ model ที่คิวรี่มาได้ คุณสามารถสร้าง per_page ใน model ได้เช่น:
class Post < ActiveRecord::Base cattr_reader :per_page @@per_page = 50 end
… หรือจะทำแบบนี้ก็ได้:
class Post < ActiveRecord::Base def self.per_page 50 end end
ถ้าคุณไม่ได้ระบุ per_page ใน model ของคุณ WillPaginate จะใช้ค่า 30 เป็นค่าดีฟอล์ต แต่คุณสามารถเปลี่ยนค่านี้ตอนเรียกใช้ controller ได้:
@posts = Post.paginate :page => params[:page] || 1, :per_page => 50
paginate finder ทำหน้าที่ครอบ finder ตัวต้นฉบับไว้และคืน collection ที่มีคุณสมบัติพิเศษเพิ่มเติมนิดหน่อย คุณสามารถใช้ collection นี้เหมือนๆกับที่คุณใช้ผลลัพทธ์ของ ActiveRecord ปกติ หรือจะส่งไปให้ view helpers ของ WillPaginate เรนเดอร์ให้ก็ได้:
<ol> <% @posts.each do |post| -%> <li><%= link_to post.title, post %></li> <% end -%> </ol>
Discussion