Como paginar en Rails 5

El presente artículo se basa en el articulo de Bala Paranj, mejor dicho es una traducción del mismo.

Me pareció muy intersante y de gran utilidad.

Pasos

Usted puede bajar el código fuente desde Paginación en Rails, que está traducido, o desde el repositorio original wpag.

Paso 1

Añada la gema al archivo Gemfile.

gem 'will_paginate'

Luego ejecute

bundle

Paso 2

Modifique el controlador de Tareas

def index
@tareas = Tarea.search(params[:term], params[:page])
end

Paso 3

Añada el helper para vista de will_paginate en la página de vista index.

<%= will_paginate @tareas %>

Paso 4

Puede jugar en la consola de Rails para ver cómo funciona el método will_paginate:

irb(main):002:0> t = Tarea.paginate(page: 1, per_page: 5)
  Tarea Load (34.6ms)  SELECT  "tareas".* FROM "tareas" LIMIT ? OFFSET ?  [["LIM
IT", 5], ["OFFSET", 0]]
   (6.3ms)  SELECT COUNT(*) FROM "tareas"
=> #<ActiveRecord::Relation [#<Tarea id: 1, nombre: "Escribir un libro", created
_at: "2017-07-16 18:23:50", updated_at: "2017-07-16 18:23:50">, #<Tarea id: 2, n
ombre: "Comprar la batería", created_at: "2017-07-16 18:23:50", updated_at: "201
7-07-16 18:23:50">, #<Tarea id: 3, nombre: "Comprar una freidora de aire", creat
ed_at: "2017-07-16 18:23:50", updated_at: "2017-07-16 18:23:50">, #<Tarea id: 4,
 nombre: "Comprar una casa", created_at: "2017-07-16 18:23:50", updated_at: "201
7-07-16 18:23:50">, #<Tarea id: 5, nombre: "Comprar un cachorro", created_at: "2
017-07-16 18:23:50", updated_at: "2017-07-16 18:23:50">]>
irb(main):003:0> t.class
=> Tarea::ActiveRecord_Relation

Podemos llamar al método de paginación con la página actual y los valores por página. Esto devuelve un objeto ActiveRelation. Podemos obtener todos los registros llamando a to_a en el objeto ActiveRelation.

irb(main):004:0> resultado = t.to_a
  Tarea Load (6.1ms)  SELECT  "tareas".* FROM "tareas" LIMIT ? OFFSET ?  [["LIMI
T", 5], ["OFFSET", 0]]
   (5.9ms)  SELECT COUNT(*) FROM "tareas"
=> [#<Tarea id: 1, nombre: "Escribir un libro", created_at: "2017-07-16 18:23:50
", updated_at: "2017-07-16 18:23:50">, #<Tarea id: 2, nombre: "Comprar la baterí
a", created_at: "2017-07-16 18:23:50", updated_at: "2017-07-16 18:23:50">, #<Tar
ea id: 3, nombre: "Comprar una freidora de aire", created_at: "2017-07-16 18:23:
50", updated_at: "2017-07-16 18:23:50">, #<Tarea id: 4, nombre: "Comprar una cas
a", created_at: "2017-07-16 18:23:50", updated_at: "2017-07-16 18:23:50">, #<Tar
ea id: 5, nombre: "Comprar un cachorro", created_at: "2017-07-16 18:23:50", upda
ted_at: "2017-07-16 18:23:50">]
irb(main):005:0> resultado.size
=> 5

Pero hay 25 tareas

irb(main):006:0> Tarea.count
   (7.0ms)  SELECT COUNT(*) FROM "tareas"
=> 25

Podemos usar el método de página proporcionado por will_paginate para paginar las tareas

irb(main):067:0> t1 = Tarea.page(1).order('id DESC')
  Tarea Load (6.6ms)  SELECT  "tareas".* FROM "tareas" ORDER BY id DESC LIMIT ?
OFFSET ?  [["LIMIT", 11], ["OFFSET", 0]]
   (6.0ms)  SELECT COUNT(*) FROM "tareas"
=> #<ActiveRecord::Relation [#<Tarea id: 25, nombre: "Leer un libro", created_at
: "2017-07-16 18:23:51", updated_at: "2017-07-16 18:23:51">, #<Tarea id: 24, nom
bre: "Volar sobre la isla", created_at: "2017-07-16 18:23:51", updated_at: "2017
-07-16 18:23:51">, #<Tarea id: 23, nombre: "Cortar madera para hacer fuego", cre
ated_at: "2017-07-16 18:23:51", updated_at: "2017-07-16 18:23:51">, #<Tarea id:
22, nombre: "Recargar la batería", created_at: "2017-07-16 18:23:51", updated_at
: "2017-07-16 18:23:51">, #<Tarea id: 21, nombre: "Obtener un corte de pelo", cr
eated_at: "2017-07-16 18:23:51", updated_at: "2017-07-16 18:23:51">, #<Tarea id:
 20, nombre: "Buscar bombilla de luz", created_at: "2017-07-16 18:23:51", update
d_at: "2017-07-16 18:23:51">, #<Tarea id: 19, nombre: "Apague la luz", created_a
t: "2017-07-16 18:23:51", updated_at: "2017-07-16 18:23:51">, #<Tarea id: 18, no
mbre: "Hacer café", created_at: "2017-07-16 18:23:51", updated_at: "2017-07-16 1
8:23:51">, #<Tarea id: 17, nombre: "Vende bebida energética", created_at: "2017-
07-16 18:23:51", updated_at: "2017-07-16 18:23:51">, #<Tarea id: 16, nombre: "Co
mprobar el binoculor", created_at: "2017-07-16 18:23:51", updated_at: "2017-07-1
6 18:23:51">, ...]>
irb(main):068:0> t1.class
=> Tarea::ActiveRecord_Relation
irb(main):069:0> t1r = t1.to_a
  Tarea Load (6.3ms)  SELECT  "tareas".* FROM "tareas" ORDER BY id DESC LIMIT ?
OFFSET ?  [["LIMIT", 30], ["OFFSET", 0]]
=> [#<Tarea id: 25, nombre: "Leer un libro", created_at: "2017-07-16 18:23:51",
updated_at: "2017-07-16 18:23:51">, #<Tarea id: 24, nombre: "Volar sobre la isla
", created_at: "2017-07-16 18:23:51", updated_at: "2017-07-16 18:23:51">, #<Tare
a id: 23, nombre: "Cortar madera para hacer fuego", created_at: "2017-07-16 18:2
3:51", updated_at: "2017-07-16 18:23:51">, #<Tarea id: 22, nombre: "Recargar la
batería", created_at: "2017-07-16 18:23:51", updated_at: "2017-07-16 18:23:51">,
 #<Tarea id: 21, nombre: "Obtener un corte de pelo", created_at: "2017-07-16 18:
23:51", updated_at: "2017-07-16 18:23:51">, #<Tarea id: 20, nombre: "Buscar bomb
illa de luz", created_at: "2017-07-16 18:23:51", updated_at: "2017-07-16 18:23:5
1">, #<Tarea id: 19, nombre: "Apague la luz", created_at: "2017-07-16 18:23:51",
 updated_at: "2017-07-16 18:23:51">, #<Tarea id: 18, nombre: "Hacer café", creat
ed_at: "2017-07-16 18:23:51", updated_at: "2017-07-16 18:23:51">, #<Tarea id: 17
, nombre: "Vende bebida energética", created_at: "2017-07-16 18:23:51", updated_
at: "2017-07-16 18:23:51">, #<Tarea id: 16, nombre: "Comprobar el binoculor", cr
eated_at: "2017-07-16 18:23:51", updated_at: "2017-07-16 18:23:51">, #<Tarea id:
 15, nombre: "Montar una moto", created_at: "2017-07-16 18:23:51", updated_at: "
2017-07-16 18:23:51">, #<Tarea id: 14, nombre: "Caminar en la arena", created_at
: "2017-07-16 18:23:51", updated_at: "2017-07-16 18:23:51">, #<Tarea id: 13, nom
bre: "Buscar pescado", created_at: "2017-07-16 18:23:51", updated_at: "2017-07-1
6 18:23:51">, #<Tarea id: 12, nombre: "Eliminar la lista de cubos", created_at:
"2017-07-16 18:23:51", updated_at: "2017-07-16 18:23:51">, #<Tarea id: 11, nombr
e: "Drive a jeep", created_at: "2017-07-16 18:23:50", updated_at: "2017-07-16 18
:23:50">, #<Tarea id: 10, nombre: "Grabar un video", created_at: "2017-07-16 18:
23:50", updated_at: "2017-07-16 18:23:50">, #<Tarea id: 9, nombre: "Desarrollar
una aplicación web", created_at: "2017-07-16 18:23:50", updated_at: "2017-07-16
18:23:50">, #<Tarea id: 8, nombre: "Escribir un artículo", created_at: "2017-07-
16 18:23:50", updated_at: "2017-07-16 18:23:50">, #<Tarea id: 7, nombre: "Elige
el ganador", created_at: "2017-07-16 18:23:50", updated_at: "2017-07-16 18:23:50
">, #<Tarea id: 6, nombre: "Ver una película", created_at: "2017-07-16 18:23:50"
, updated_at: "2017-07-16 18:23:50">, #<Tarea id: 5, nombre: "Comprar un cachorr
o", created_at: "2017-07-16 18:23:50", updated_at: "2017-07-16 18:23:50">, #<Tar
ea id: 4, nombre: "Comprar una casa", created_at: "2017-07-16 18:23:50", updated
_at: "2017-07-16 18:23:50">, #<Tarea id: 3, nombre: "Comprar una freidora de air
e", created_at: "2017-07-16 18:23:50", updated_at: "2017-07-16 18:23:50">, #<Tar
ea id: 2, nombre: "Comprar la batería", created_at: "2017-07-16 18:23:50", updat
ed_at: "2017-07-16 18:23:50">, #<Tarea id: 1, nombre: "Escribir un libro", creat
ed_at: "2017-07-16 18:23:50", updated_at: "2017-07-16 18:23:50">]
irb(main):070:0> t1r.size
=> 25

Paso 6

Utilicemos el método de paginación proporcionado por will_paginate en el modelo de tarea.

def self.search(term, page)
  if term
    where('nombre LIKE ?', "%#{term}%").paginate(page: page, per_page: 5).order('id DESC')
  else
    paginate(page: page, per_page: 5).order('id DESC') 
  end
end

Esta paginación ahora funciona para un listado completo en el index y como resultado de búsqueda.

Paso 7

La vista index de tareas deberá lucir como el siguiente código:

<p id="notice"><%= notice %></p>

<h1>Tareas</h1>
<%= form_tag(tareas_path, method: :get) do %>
   <%= text_field_tag :term, params[:term] %>
   <%= submit_tag 'Buscar', nombre: nil %>
<% end %>
<table>
  <thead>
    <tr>
      <th>Nombre</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @tareas.each do |tarea| %>
      <tr>
        <td><%= tarea.nombre %></td>
        <td><%= link_to 'Show', tarea %></td>
        <td><%= link_to 'Edit', edit_tarea_path(tarea) %></td>
        <td><%= link_to 'Destroy', tarea, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New Tarea', new_tarea_path %>

<%= will_paginate @tareas %>

Paso 8

Puede personalizar la apariencia y la sensación de paginación. Copie el siguiente CSS de will_paginate a su application.css

.digg_pagination {
  background: white;
  cursor: default;
  /* self-clearing method: */ }
  .digg_pagination a, .digg_pagination span, .digg_pagination em {
    padding: 0.2em 0.5em;
    display: block;
    float: left;
    margin-right: 1px; }
  .digg_pagination .disabled {
    color: #999999;
    border: 1px solid #dddddd; }
  .digg_pagination .current {
    font-style: normal;
    font-weight: bold;
    background: #2e6ab1;
    color: white;
    border: 1px solid #2e6ab1; }
  .digg_pagination a {
    text-decoration: none;
    color: #105cb6;
    border: 1px solid #9aafe5; }
    .digg_pagination a:hover, .digg_pagination a:focus {
      color: #000033;
      border-color: #000033; }
  .digg_pagination .page_info {
    background: #2e6ab1;
    color: white;
    padding: 0.4em 0.6em;
    width: 22em;
    margin-bottom: 0.3em;
    text-align: center; }
    .digg_pagination .page_info b {
      color: #000033;
      background: #6aa6ed;
      padding: 0.1em 0.25em; }
  .digg_pagination:after {
    content: ".";
    display: block;
    height: 0;
    clear: both;
    visibility: hidden; }
  * html .digg_pagination {
    height: 1%; }
  *:first-child + html .digg_pagination {
    overflow: hidden; }

.apple_pagination {
  background: #f1f1f1;
  border: 1px solid #e5e5e5;
  text-align: center;
  padding: 1em;
  cursor: default; }
  .apple_pagination a, .apple_pagination span {
    padding: 0.2em 0.3em; }
  .apple_pagination .disabled {
    color: #aaaaaa; }
  .apple_pagination .current {
    font-style: normal;
    font-weight: bold;
    background-color: #bebebe;
    display: inline-block;
    width: 1.4em;
    height: 1.4em;
    line-height: 1.5;
    -moz-border-radius: 1em;
    -webkit-border-radius: 1em;
    border-radius: 1em;
    text-shadow: rgba(255, 255, 255, 0.8) 1px 1px 1px; }
  .apple_pagination a {
    text-decoration: none;
    color: black; }
    .apple_pagination a:hover, .apple_pagination a:focus {
      text-decoration: underline; }

.flickr_pagination {
  text-align: center;
  padding: 0.3em;
  cursor: default; }
  .flickr_pagination a, .flickr_pagination span, .flickr_pagination em {
    padding: 0.2em 0.5em; }
  .flickr_pagination .disabled {
    color: #aaaaaa; }
  .flickr_pagination .current {
    font-style: normal;
    font-weight: bold;
    color: #ff0084; }
  .flickr_pagination a {
    border: 1px solid #dddddd;
    color: #0063dc;
    text-decoration: none; }
    .flickr_pagination a:hover, .flickr_pagination a:focus {
      border-color: #003366;
      background: #0063dc;
      color: white; }
  .flickr_pagination .page_info {
    color: #aaaaaa;
    padding-top: 0.8em; }
  .flickr_pagination .previous_page, .flickr_pagination .next_page {
    border-width: 2px; }
  .flickr_pagination .previous_page {
    margin-right: 1em; }
  .flickr_pagination .next_page {
    margin-left: 1em; }

Haga los cambios apropiados en el index para que tome las clases css.

<div class="apple_pagination">
  <div class="page_info">
    <%= page_entries_info @tasks %>
  </div>
  <%= will_paginate @tasks, :container => false %>
</div>

Puede cambiar el aspecto de la paginación cambiando la clase a las clases definidas en el archivo application.css para flickr, apple o digg.

Resumen

En este artículo he mostrado como usar la gema will_paginate para paginar objetos ActiveRecord en Rails 5. También he mostrado como personalizar la apariencia de la paginación

Avatar
Carlos Dagorret
CTO Facultad de Ciencias Económicas

My research interests include distributed robotics, mobile computing and programmable matter.

comments powered by Disqus