Делаем простую пагинацию в Rails 3 ч. 2

августа 24, 2011  |  Published in Ruby on Rails, Ruby on Rails 3  |  3 Comments

В предыдущей статье мы сделали самую простую пагинацию, которая выводит ссылки на все существующие страницы. В этой статье мы несколько расширим функционал.

 

 

 

Для начала откроем хелпер постов:

#../app/helpers/posts_helper.rb
module PostsHelper
end

В этот хелпер мы поместим весь код отвечающий за представление ссылок пагинации.
Сразу оговорюсь (предсказывая гневные комментарии типа: «Что за говнокод?»), что данная статья не ставит целью описать окончательный вариант разработки пагинации. Рефакторинг, добавление конфигурирования представления ссылок и т.д. будет рассмотрено в следующей статье или статьях. Это пошаговое руководство разработки пагинации, которое показывает не только правильный вариант пагинации, но и попутно демонстрирует распространенные у новичков ошибки.

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

Ниже привожу код с комментариями:

module PostsHelper
  #Использую этот метод для получения массива ссылок
  def page_links
    pg_links = []
    Post.pgcount.times do |pg|
      #индексация массива начинается с единицы
      p = pg+1
      pg_links[p] = link_to(p, "/posts/#{p}")
    end
    #возвращаем массив строк - ссылок на все страницы
    return pg_links
  end

  def paginate(style = :full_list)
    #переменная pg_html хранит строку - html код отображения пагинации
    pg_html = ""
    #Если params["page"] не определен(в адресной строке нет номера страницы), то номер текущей страницы = 1
    params["page"] ? current_page = params["page"].to_i : current_page = 1
    pg_links = page_links
    #проверяем какой режим выбран
    case style
    #если :full_list, то выводим ссылки на все страницы
    when :full_list  then
      pg_links.each_with_index do |page,key|
        if key == current_page.to_i
          pg_html += "<span class=\"page_link current_page\">#{page}</span>"
        elsif !page.nil?
          pg_html += "<span class=\"page_link\">#{page}</span>"
        end
      end
    #если :short_list, то выводим ссылки на первую, последнюю и соседние страницы (по 2 с каждой стороны от текущей)
    when :short_list then
      pg_html += "<span class=\"page_link first_page\"><b>#{pg_links[1]}</b></span>"

      if current_page > 3
        pg_html += "<span class=\"page_link\"><b>#{pg_links[current_page-2]}</b></span>"
      end

      if current_page > 2
        pg_html += "<span class=\"page_link\"><b>#{pg_links[current_page-1]}</b></span>"
      end

      if current_page > 1 and current_page < pg_links.size
        pg_html += "<span class=\"page_link current_page\"><b>#{pg_links[current_page]}</b></span>"
      end

      if current_page < pg_links.count - 2
        pg_html += "<span class=\"page_link\"><b>#{pg_links[current_page+1]}</b></span>"
      end

      if current_page < pg_links.count - 3
        pg_html += "<span class=\"page_link\"><b>#{pg_links[current_page+2]}</b></span>"
      end

      pg_html += "<span class=\"page_link last_page\"><b>#{pg_links.last}</b></span>"
    #если вибран режим :prev_next, то показываем только ссылкии на предыдущую страницу и следующую
    when :prev_next then
      if current_page > 1
        pg_html += "<span class=\"page_link prev_page\"><b>#{pg_links[current_page - 1]}</b></span>"
      end

      if current_page < pg_links.size
        pg_html += "<span class=\"page_link next_page\"><b>#{pg_links[current_page + 1]}</b></span>"
      end
    end
    #возвращаем html-код представляющий ссылки
    return raw pg_html
  end
end

Для того, чтобы ссылки отображались красиво, мы обернули их в <span></span> и присвоили им стили. Давайте откроем файл со стилями и определим свойства классов: page_link, current_page, first_page, last_page, prev_page и next_page:

/*../public/stylesheets/paginate.css*/
div#paginate{
  width:100%;
  background:#A4C639;
  overflow:hidden;
  padding:5px 0;
}

span.page_link{
  float:left;
  padding:2px;
  border:1px solid #008000;
  margin-left:5px;
  background:#8DB600;
  margin-top:5px;
  line-height:1em;
}

.page_link a, .page_link a:visited {
  color:#fff;
  font-size:10px;
  display:block;
}
.page_link a:hover{
  color:#FDEE00;
  background:none;
}

span.current_page{
  border:1px solid #B31B1B;
  background:#EB4C42;
}

span.first_page, span.last_page{
  border:1px solid #2A52BE;
  background:    #4997D0;
}

Теперь вы можете в шаблоне ../app/views/index.html.erb использовать метод paginate. Ниже приведены примеры представления ссылок при различных режимах. Как не сложно догадаться по приведенному выше CSS-коду, хэлпер представляющий ссылки помещен в <div id=»paginate»></div> для большей привлекательности представления.

<%= paginate #по умолчанию используется :full_list %>

<%= paginate(:short_list) %>

<%= paginate(:prev_next) %>


На этом все, спасибо за внимание!

Лучшая благодарность автору — ваши комментарии!

Tags: ,

Responses

  1. Anton says:

    августа 25, 2011 at 08:47 (#)

    Предлагаю парочку улучшений:

    вместо:

    params["page"] ? current_page = params["page"].to_i : current_page = 1

    напрашивается:

    current_page = (params["page"] || 1).to_i

    А вместо:

      def page_links
        pg_links = []
        Post.pgcount.times do |pg|
          p = pg+1
          pg_links[p] = link_to(p, "/posts/#{p}")
        end
        return pg_links
      end
    

    читабельнее сделать:

      def page_links
        Array.new(Post.pgcount) do |i|  
          index = i+1
          link_to(index, "/posts/#{p}")
        end
      end
    
  2. admin says:

    августа 25, 2011 at 09:42 (#)

    Спасибо, Антон, реально красивее и короче код.

  3. Kir says:

    августа 27, 2011 at 09:10 (#)

    Почему бы не использовать kaminari?

Leave a Response

Для подсветки кода используйте BB - коды: [language]...[/language], где language может быть: ruby, javascript, css, html.