Зная способы улучшить скромный быт разработчика, мне порой до слез больно смотреть, как люди корячатся над простейшими задачами. Одной из таких задач является вывод коллекции объектов (новостей, картинок, товаров в каталоге) с разбивкой по страницам.
Чаще всего эта задача реализуется через стандартный модуль Pagination, встроенный в Rails. К счастью, в Edge эта безумная кувалда вынесена в отдельный плагин, дабы не смущать умы честных разработчиков. Стандартный Pagination невероятно медленный и громоздкий. Слишком много ненужного хлама вокруг достаточно простой задачи. Есть гораздо более удобное решение задачи разбивки объектов по страницам - плагин will_paginate.
Использование
В плагине will_paginate вся логика разбивки коллекции по страницам вынесена в модель. Вместо того, чтобы создавать отдельно объект для страниц и отдельно для коллекции данных, will_paginate при выборке создает прокси-объект, который одновременно отвечает и за страницы, и за данные.
Выборка данных выглядит следующим образом:
@posts = Post.paginate :page => params[:page]
В переменную @page будет выбрана коллекция объектов, расположенных на странице с номером params[:page]. С этой переменной можно работать точно так же, как с массивом объектов, выбранных методом find. Однако, кроме стандартных методов коллекции, у этой переменной добавляются следующие методы:
current_page- текущая страница (по умолчанию 1)per_page- количество объектов на страницу (по умолчанию 30)total_entries- общее число объектов на всех страницахpage_count- общее число страницoffset- текущее смещение (на первой странице смещение равно 0)previous_page- номер предыдущей страницыnext_page- номер следующей страницы
Методу paginate можно передавать параметры точно так же, как методу find:
@posts = Post.paginate :conditions => ["publicated = ?", true],
:order => "date",
:page => params[:page]
Кроме того, можно использовать "магические" методы paginate_by_*:
@posts = Post.paginate_by_publicated(true, :order => "date", :page => params[:page])
Выборки данных в этом случае будут осуществляться с помощью методов find_all_by_*. В данном примере с помощью find_all_by_publicated.
Мало того, выборку можно делать не только для класса, но и для связанных объектов (например, через has_many):
@posts = @user.posts.paginate :page => params[:page]
По умолчанию коллекция разбивается на страницы по 30 объектов, однако это значение можно изменить, задав для класса переменную per_page:
class Post < ActiveRecord::Base
cattr_reader :per_page
@@per_page = 10
end
или
class Post < ActiveRecord::Base
def self.per_page
return 10
end
end
Вывод данных и нумератора страниц в шаблонах реализуется более чем просто:
<h1>Мои записи</h1>
<% @posts.each do |post| %>
<p><%= post.title %></p>
<% end %>
<b>Страницы:</b>
<%= will_paginate @posts %>
Собственно, это всё :) Согласитесь, гораздо проще, чем дефолтный Pagination.
Установка
ruby script/plugin install svn://errtheblog.com/svn/plugins/will_paginate