Web,ruby, Ajax ou qualquer outra coisa que me venha a cabeça (com prioridade para esta última)

24 janeiro, 2006

RoR: Como Paginar

Paginação Simples

Usar o ajudante de paginação

Paginação à medida

O método de paginação embutido no RoR torna-se limitado quando as suas necessidades se tornam mais complexas. É então necessário usar uma técnica melhor:

O método do Kevin de paginação à medida implica usar quatro passos.

No controlador:


def list
  #passo 1: ler e atribuir valores às variáveis que necessitamos
  page = (params[:page] ||=1).to_i
  items_per_page = 20
  offset = (page -1) * items_per_page

  #passo 2: efectuar o seu find à medida efectuando 
  #qualquer tipo de limites ou deslocamentos
  # isto é obter tudo em cada página, não se 
  #preocupar com paginação por agora
  @items = Item.find_com_algum_metodo_a_medida(@alguma_variavel)

  #passo 3: criar um Paginator, a segunda variável
  #tem que ser o número da TOTALIDADE dos items em TODAS as páginas
  @item_pages = Paginator.new(self, @items.length, items_per_page, page)

  #passo 4: só enviar um subconjunto de @items para a vista
  # é aqui que ocorre a magia. Não é necessário voltar a
  # fazer outra busca  (find)
  @items = @items[offset..(offset + items_per_page - 1)]

end

Na vista colocar:


Pages: 
<%= link_to('previous', {:params => params.merge('page' => 
@ item_pages.current.previous)}) +
 ' ' if @ item_pages.current.previous %>

<% for page in @ item_pages -%>
<%= link_to_unless(params[:page].to_i == page.number, page.number,
 {:params => params.merge('page' => page)}) %> 
<% end -%>

<%= link_to('next', {:params => params.merge('page' => 
@item_pages.current.next)}) if @ item_pages.current.next %>

Esta técnica funciona com conjuntos de dados pequenos e médios (onde não tem que se preocupar com um grande número de registos, embora não os queira ver surgir de uma só vez), mas torna-se limitada quando os registos são em elevado número.

Para grandes conjuntos de dados que necessitem de buscas à medida, necessita de saber o número total de registo, depois criar um Paginador e depois só recuperar os registos desejados.

No controlador:


def list
    # passos 1: ler e atribuir variáveis necessárias
    page = (params[:page] ||= 1).to_i
    items_per_page = 20
    offset = (page - 1) * items_per_page

    # passo 2: em vez de efectuar uma busca completa descobrir
    # só o número de registo
    @item_count = Item.find_record_count(@some_variable)

    # passo 3: criar um Paginator, a segunda variável tem 
    #que ser o número de TODOS os items em TODAS as páginas
    @item_pages = Paginator.new(self, @item_count, items_per_page, page)

    # passo 4: descobrir só o subconjunto pedido de @items
    @items = 
    Item. busca_com_algum_metodo_a_medida(@some_variable, 
                                          offset,
                                          items_per_page)

end

Depois necessitará de alterar o método "busca_com_algum_metodo_a_medida" de forma a usar as variáveis offset e items_per_page numa cláusula SQL LIMIT. Se o que descobrir for já complexo, poderá ser mais fácil usar "find_by_sql" em vez de "find".

O código da sua vista pode ser igual ao anterior.

Sem comentários: