Recentemente, comecei a desenvolver algumas aplicações menores usando o RubyUI, com o objetivo de aprender mais sobre desenvolvimento de views aproveitando ao máximo o que o Rails oferece. Este pode ser o primeiro de alguns posts onde compartilho soluções legais que consegui criar ao combinar tecnologias do ecossistema Rails para otimizar o desenvolvimento de interfaces.
Neste artigo, vou mostrar como criei uma view de paginação reutilizável, usando os componentes do RubyUI junto com a gem Pagy.
Obs.: O Pagy já oferece helpers prontos para uso direto em HTML/ERB, mas achei interessante criar meu próprio componente para poder estilizar a paginação do meu jeito e criar variações conforme as necessidades do projeto.
Pré-requisitos
Instalar o RubyUI.
Adicionar gem Pagy (por motivos de performance, é a gem mais indicada atualmente para paginação).
gem 'pagy', '~> 9.3'
Adicionar alguma biblioteca de icons (escolhi a lucide_icon, mas fica a critério de vocês).
gem 'lucide-rails', '~> 0.5.1'
Implementação
- Importei os componentes prontos de Paginação e Botões.
rails g ruby_ui:component Button
rails g ruby_ui:component Pagination
- Configurei as bibliotecas no Views::Base (considerando que Components::Base contém as configurações do RubyUI e Phlex para rodar os componentes).
# app/views/base.rb
class Views::Base < Components::Base
include Pagy::Frontend
register_output_helper :lucide_icon
end
- Criei um componente Wrapper para setar padrões de div e adicionei a ele um específico com o formato para paginação (esse passo é opcional e pode ser adicionado direto na view que desejar).
module RubyUI
class Wrapper < Base
VARIANTS = %i[... pagination].freeze
def initialize(variant: :default, **attrs)
@variant = variant.to_sym
super(**attrs)
end
def view_template(&block)
case @variant
(...)
when :pagination then pagination_wrapper(&block)
end
end
(...)
def pagination_wrapper(&block)
div(class: 'mt-6', &block)
end
(...)
end
end
- Então criei uma partial
app/views/shared/pagination.rb
# app/views/shared/pagination.rb
module Views
module Shared
class Pagination < Views::Base
def initialize(pagy:, request:)
@pagy = pagy
@request = request
end
def view_template
return if @pagy.pages <= 1
Wrapper(variant: :pagination) do
Pagination do
PaginationContent do
render_first_page
render_prev_page
render_pages
render_next_page
render_last_page
end
end
end
end
private
def request
@request
end
def render_first_page
return if @pagy.page == 1
PaginationItem(href: pagy_url_for(@pagy, 1)) do
lucide_icon('chevrons-left')
end
end
def render_prev_page
return if @pagy.prev.nil?
PaginationItem(href: pagy_url_for(@pagy, @pagy.prev)) do
lucide_icon('chevron-left')
end
end
def render_pages
current_page = @pagy.page
total_pages = @pagy.pages
pages_to_show = [
current_page - 1,
current_page,
current_page + 1
].select { |page| page.between?(1, total_pages) }
pages_to_show.each do |page|
PaginationItem(href: pagy_url_for(@pagy, page), active: page == current_page) { page.to_s }
end
end
def render_next_page
return if @pagy.next.nil?
PaginationItem(href: pagy_url_for(@pagy, @pagy.next)) do
lucide_icon('chevron-right')
end
end
def render_last_page
return if @pagy.page == @pagy.pages
PaginationItem(href: pagy_url_for(@pagy, @pagy.pages)) do
lucide_icon('chevrons-right')
end
end
end
end
end
Ao final, a paginação aparecerá assim:
Ela é customizável, portanto, basta remover ou adicionar algo ao view_template definido. Por exemplo, se não quiser as setas de Início e Final, basta remover os renders render_last_page
e render_first_page
.
(...)
def view_template
return if @pagy.pages <= 1
Wrapper(variant: :pagination) do
Pagination do
PaginationContent do
render_prev_page
render_pages
render_next_page
end
end
end
end
(...)
A visualização ficará assim:
É possível adicionar texto também, configurando os PaginationItem, como no exemplo:
(...)
def render_prev_page
return if @pagy.prev.nil?
PaginationItem(href: pagy_url_for(@pagy, @pagy.prev)) do
lucide_icon('chevron-left')
plain "Prévia"
end
end
(...)
A visualização ficará assim:
Uso
Pode configurar seguindo o padrão do pagy em seu Controller:
# Wrap your collections with pagy in your actions
@pagy, @records = pagy(Record.all)
E você pode chamar a partial passando o @pagy e o request (que já vai por padrão no controller), exemplo:
render Views::Shared::Pagination.new(pagy: @pagy, request: request)
Um controller simples ficaria assim:
class PostController < ApplicationController
def index
@pagy, @posts = pagy(Post.all, limit: 42)
render Views::Shared::Pagination.new(pagy: @pagy, request: request)
end
end
Obrigada pela leitura! Qualquer dúvida ou módulo que achem relevante de ser adicionado, fiquem a vontade para compartilhar.
Lembrando que para ser mais concisa, não mostrei detalhes de instalação e configuração de algumas coisas necessárias, mas basta seguir os tutoriais detalhados de cada ferramenta.
Ferramentas:
- RubyUI: https://rubyui.com/
- Pagy: https://github.com/ddnexus/pagy
- LucideRails: https://github.com/heyvito/lucide-rails
Top comments (0)