Сам я только новичок в изучении RoR, но при разработке собственного проекта возникло желание вместо классической пагинации с помощью гема will_paginate сделать ее более удобной при помощи javascript. Это должна быть классическая кнопка, при нажатии на которую загружаются следующие n-записей. Решение проблемы на русском языке я не нашел, на английском есть, но я нашел только громоздкие и неудобные варианты. Как говорится, хочешь сделать что-то хорошо — сделай это сам. Вот что получилось.
Разбиение на страницы будем производить с помощью все того же гема will_paginate, также мы будем его использовать если javascript у пользователя отключен.
Итак сначала устанавливаем гем:
gem 'will_paginate'
bundle install
Затем начинаем с контроллера. В моем случае это будет разбиение на страницы списка пользователей. Соответственно это действие 'index', которое должно отвечать на javascript (:js) запрос:
respond_to :html, :xml, :json, :js
def index
@users = User.paginate(page: @@page)
respond_with @users
end
Переменная класса
@@page
используется в качестве счетчика. Чуть позже мы к ней вернемся.
Далее идем во вьюху index.html.erb и добавляем пагинацию:
<h1>All users</h1>
<ul class="users">
<%= render @users %>
</ul>
<div id="without_button">
<%= will_paginate @users %>
</div>
<% if @users.next_page %>
<div id="load_more_users">
<%= button_to 'More users', {action: "index", new_req: true }, method: :get, remote: true, class: "btn btn-primary btn-large" %>
</div>
<% end %>
Поясню несколько моментов. Здесь у нас два блока. Первый c id «without_button» добавляет стандартную строку гема по разбиению страниц. Ее мы будем использовать когда javascript отключен:
Второй блок включает кнопку. Она будет показана только если количество юзеров достаточно для разбения на записи. По умолчанию для will_paginate это 30 записей. Соответственно если их 30 и меньше, метод next_page возвратит nil и блок загружен не будет. Если javascript отключен, кнопки быть не должно. Соответственно прописываем в css:
#load_more_users {
display: none;
}
Кнопка передает управление нашему действию c хэшем params[:new_req], значение которого мы уставливаем в true. Объяснение будет дальше.
Итак теперь мы должны понять, что нам нужно загрузить следующие записи. Причем счетчик должен быть равным 1 (первая страница) при загрузке или обновлении страницы. Здесь нам помогает params[:new_req], пока не нажата кнопка он равен nil, если же равен true, то увеличиваем значение счетчика на 1. Еще один момент, если javascript отключен, то пагинация будет происходить через хэш params[:page]. А значит его значение мы и будем присваивать cчетчику. Надеюсь доступно объяснил. Итак мы создаем следующим метод:
private
def up_page
if params[:new_req]
@@page+=1
elsif params[:page]
@@page=params[:page]
else
@@page=1
end
end
Переменная класса используется потому, что переменная экземпляра создается заново каждый раз при новом обращении к действию.
Метод должен выполняться перед действием index:
before_action :up_page, only: :index
Теперь самое интересное. Переходим к СoffeeScript. Добавлем следующий код в файл app/assets/javascripts/users.js.coffee
$('#with_button').hide()
$('#load_more_users').show()
$('#load_more_users form').after('<button class="btn btn-primary btn-large btn-clone disabled" style="display: none;">More users</button>')
$('#load_more_users').click ->
$('#load_more_users').find('form').hide().siblings('button').show()
Первая строчка скрывает классическую пагинацию, вторая показывает кнопку. Затем после нашей кнопки мы добавляем вторую кнопку-клона с затемненным фоном, которая будет показана вместо первой кнопки при клике на нее. В принципе кнопка-клон здесь не обязательна. Вместо нее можно показывать строку загрузки или любую другую картинку/гифку.
Осталось подключить Ajax. Добавляем следующий код в index.js.erb:
$('.users').append('<%= j render @users %>').siblings('#load_more_users').find("button").hide().siblings('form').show();
<% unless @users.next_page %>
$('#load_more_users').remove();
<% end %>
После загрузки следующих n-записей пользователей мы скрываем кнопку-клона и снова показываем нашу форму с первой кнопкой. Кнопку-клона мы создаем для того, чтобы предотвратить повторное нажатие на кнопку, пока не загрузятся записи. Ну и удаляем нашу кнопку, когда все записи из нашего массива ActiveRecord::Relation уже показаны.
Вот и все. Надеюсь эта информация будет кому-нибудь полезна.
Автор: dnom