Динамическая подгрузка записей в Ruby on Rails

В прошлой статье мы рассматривали постраничную навигацию. Сегодня же мы попробуем сделать подгрузку записей как в ВКонтакте. Т.е. загрузка новых записей будет происходить при достижении конца страницы и без полной перезагрузки страницы.

Автор . Дата: 08.11.2014

В прошлой статье мы рассматривали постраничную навигацию. Сегодня же мы попробуем сделать подгрузку записей как в ВКонтакте. Т.е. загрузка новых записей будет происходить при достижении конца страницы и без полной перезагрузки страницы.

Прежде всего, у нас должны быть записи, которые будут выводиться, и страница, на которой они будут выводиться. Создадим простую вьюху для этого:

<% @records.each do |record| %>
    <div>
        <h2><%= record.title %></h2>
        <p><%= record.text %></p>
    </div>
<% end %>

<a href="/records/?page=<%= params[:page] %>" id="next-btn" data-page="<%= params[:page] %>">Ещё</a>


 

У нас есть ссылка Ещё. Она имеет обычную ссылку для того, чтобы поисковые роботы и люди без включенного JavaScript могли переходить по следующим страницам, атрибут id, который нужен для того, чтобы мы могли найти нашу ссылку в JavaScript коде, и атрибут data-page, который будет содержать номер следующей страницы. Наш контроллер будет выглядеть примерно следующим образом:

def index:
    @records = Record.all.paginate(:page => params[:page], :per_page => 20)
    params[:page] = 1 if params[:page].nil?
    params[:page] += 1
end

Здесь мы выбираем 10 записей с помощью гема will_paginate и увеличиваем номер страницы на 1. Это нужно для нашей кнопки Ещё. Теперь при клике на кнопку Ещё мы будем переходить на следующую страницу. Но нам ведь нужно сделать подгрузку записей без перехода на следующую страницу. Для этого добавим скрипт на кнопку Еще:

$(document).ready(function()
    $('#next-btn').scroll(function(event){
        if ($(window).scrollTop() + $(window).height() >= $('#next-btn').offset().top) {
            $(window).unbind('scroll');        
            var btn = this;

            if (!$(btn).data('page'))
                return;

            $(btn).hide();

            $.ajax({
                url: '/records/ajax',
                type: 'POST',
                async: false,
                data: {
                    page: $(this).attr('data-page')
                },
                dataType: 'JSON'
            }).done(function (data) {
                if (data.records && $.isArray(data.records)) {
                    $( "#record-tmpl" )
                        .tmpl( data.records )
                        .insertBefore( btn );
                        
                    if (data.page) {
                        $(btn).attr('data-page', data.page)
                        $(btn).show();
                    }
                }
            });
        }
    });
});

В этом скрипты мы создаем событие при показе кнопки Еще на экране, скрываем её для того, чтобы не мозолить глаза людям, после чего делаем AJAX запрос к нашему контроллеру, который будет висеть на маршруте /records/ajax. Мы передаем номер следующей страницы и когда контроллер вернет результаты своей работы, мы проверим JSON массив records на корректность и вызовем функцию tmpl реализуемую плагином jQuery Tmpl. Она из шаблона и массива с новыми записями сгенерирует готовый html код, который мы вставим перед нашей кнопкой. И если есть ещё записи, в массиве прийдет номер следующей страницы, который мы обновим у нашей кнопки.

Нам так же нужен текст шаблона:

<script id="record-tmpl" type="text/x-jquery-tmpl">
    <div>
        <h2>${title}</h2>
        <p>${text}</p>
    </div>
</script>

Не забываем скачать и подключить плагин jQuery Tmpl. Теперь нам нужно создать экшен, который будет обрабатывать наши AJAX запросы:

def ajax
  records = Record.all.paginate(:page => params[:page], :per_page => 20)
  result = {}
  result["records"] = records
  if (params[:page] + 1) * 20 < Records.all.size
    result["page"] = params[:page] + 1
  end
  render json: result
end

Вот собственно и все :-)


comments powered by HyperComments