Action View no Rails: Dominando Templates, Formulários e Helpers

Action View no Rails: Dominando Templates, Formulários e Helpers

Action View representa a camada de visualização da nossa trilogia MVC no Rails, encapsulando toda a funcionalidade necessária para renderizar templates e gerar HTML, XML ou JavaScript de volta para o usuário. Neste tutorial prático, vamos explorar desde conceitos fundamentais até técnicas avançadas de organização e manutenção de views.

Templates: O Coração das Views

Para dominar o Action View, precisamos entender três aspectos fundamentais dos templates: onde eles ficam, o ambiente em que executam e o que contêm.

Organização e Estrutura de Templates

O método render() espera encontrar templates no diretório app/views da aplicação atual. A convenção estabelece um subdiretório separado para as views de cada controller:

# Estrutura de diretórios para templates
app/views/
  produtos/
    index.html.erb
    show.html.erb
    edit.html.erb
  loja/
    index.html.erb
    carrinho.html.erb

# Renderização flexível de templates
render(action: 'nome_acao_falsa')
render(template: 'controller/nome')
render(file: 'diretorio/template')

Ambiente de Execução dos Templates

Templates executam em um ambiente rico que fornece acesso completo às informações configuradas pelo controller:

<!-- Template de debug para desenvolvimento -->
<h4>Sessão</h4> <%= debug(session) %>
<h4>Parâmetros</h4> <%= debug(params) %>
<h4>Resposta</h4> <%= debug(response) %>

Formulários: Coletando Dados dos Usuários

O Rails oferece uma coleção abrangente de helpers para gerar formulários HTML de forma elegante e funcional. Vamos construir um formulário completo que demonstra os principais tipos de entrada:

<%= form_for(:modelo) do |formulario| %>
  <p>
    <%= formulario.label :entrada %>
    <%= formulario.text_field :entrada, :placeholder => 'Digite o texto aqui...' %>
  </p>

  <p>
    <%= formulario.label :endereco %>
    <%= formulario.text_area :endereco, :rows => 3, :cols => 40 %>
  </p>

  <!-- Botões de rádio para seleção única -->
  <p>
    <%= formulario.label :cor %>:
    <%= formulario.radio_button :cor, 'vermelho' %>
    <%= formulario.label :vermelho %>
    <%= formulario.radio_button :cor, 'amarelo' %>
    <%= formulario.label :amarelo %>
  </p>

  <!-- Checkboxes para seleção múltipla -->
  <p>
    <%= formulario.label 'condimento' %>:
    <%= formulario.check_box :ketchup %>
    <%= formulario.label :ketchup %>
    <%= formulario.check_box :mostarda %>
    <%= formulario.label :mostarda %>
  </p>
<% end %>

Upload de Arquivos: Implementação Completa

Para implementar upload de arquivos, precisamos configurar o formulário, model e controller adequadamente. Vamos criar um sistema de upload de imagens:

# Migration para tabela de imagens
class CreateImagens < ActiveRecord::Migration
  def change
    create_table :imagens do |t|
      t.string :comentario
      t.string :nome
      t.string :tipo_conteudo
      t.binary :dados, :limit => 1.megabyte
    end
  end
end

# Model com validação e processamento de upload
class Imagem < ActiveRecord::Base
  validates_format_of :tipo_conteudo,
                      with: /\Aimage/,
                      message: "deve ser uma imagem"
  
  def imagem_enviada=(campo_imagem)
    self.nome = extrair_nome_base(campo_imagem.original_filename)
    self.tipo_conteudo = campo_imagem.content_type.chomp
    self.dados = campo_imagem.read
  end

  private
  
  def extrair_nome_base(nome_arquivo)
    File.basename(nome_arquivo).gsub(/[^\w._-]/, '')
  end
end

O formulário de upload requer configuração específica para multipart/form-data:

<%= form_for(:imagem,
             url: {action: 'salvar'},
             html: {multipart: true}) do |form| %>
  
  Comentário: <%= form.text_field("comentario") %><br/>
  
  Envie sua imagem: <%= form.file_field("imagem_enviada") %><br/>
  
  <%= submit_tag("Enviar arquivo") %>
<% end %>

Helpers: Estendendo a Funcionalidade das Views

Helpers são módulos que encapsulam métodos de saída, mantendo as views limpas e organizadas. O Rails oferece helpers integrados poderosos e permite criar helpers personalizados.

Helpers de Formatação Integrados

<!-- Helpers de tempo e data -->
<%= distance_of_time_in_words(Time.now, Time.local(2024, 12, 25)) %>
# => "aproximadamente 2 meses"

<%= time_ago_in_words(Time.local(2024, 10, 15)) %>
# => "há 5 meses"

<!-- Helpers de formatação numérica -->
<%= number_to_currency(1234.56) %>
# => "R$ 1.234,56"

<%= number_to_currency(234.56, unit: "US$", precision: 0) %>
# => "US$ 235"

<%= number_to_human_size(123456) %>
# => "120,6 KB"

<%= number_to_percentage(66.66666, precision: 1) %>
# => "66,7%"

Helpers de Links e Navegação

<!-- Link básico -->
<%= link_to "Adicionar Comentário", new_comentarios_path %>

<!-- Link com confirmação e método HTTP específico -->
<%= link_to "Deletar", produto_path(@produto),
                method: :delete,
                data: { confirm: 'Tem certeza?' },
                class: "perigoso" %>

<!-- Menu com link condicional -->
<ul>
<% %w{ criar listar editar salvar }.each do |acao| %>
  <li>
    <%= link_to_unless_current(acao.capitalize, action: acao) %>
  </li>
<% end %>
</ul>

<!-- Link de email com obfuscação -->
<%= mail_to("suporte@minhaempresa.com.br", "Contatar Suporte",
           subject: "Pergunta de suporte de #{@usuario.nome}",
           encode: "javascript") %>

Criando Helpers Personalizados

# app/helpers/loja_helper.rb
module LojaHelper
  def titulo_pagina
    @titulo_pagina || "Loja Pragmática"
  end
  
  def formatar_preco_brasileiro(valor)
    number_to_currency(valor, unit: "R$ ", separator: ",", delimiter: ".")
  end
  
  def status_pedido_estilizado(status)
    classes_css = case status
                   when 'pendente'
                     'status-pendente amarelo'
                   when 'processando'
                     'status-processando azul'
                   when 'concluido'
                     'status-concluido verde'
                   else
                     'status-desconhecido cinza'
                   end
                   
    content_tag(:span, status.capitalize, class: classes_css)
  end
end

Layouts e Partials: Organizando a Estrutura

Layouts e partials são fundamentais para manter o código DRY (Don't Repeat Yourself) e facilitar a manutenção das views.

Estrutura de Layouts Dinâmicos

<!-- app/views/layouts/application.html.erb -->
<!DOCTYPE html>
<html>
  <head>
    <title><%= @titulo || "Minha Aplicação Rails" %></title>
    <%= stylesheet_link_tag 'application' %>
    <%= javascript_importmap_tags %>
    
    <!-- Conteúdo específico da página -->
    <%= yield :head %>
  </head>

  <body>
    <header>
      <h1><%= @titulo %></h1>
    </header>

    <div class="container">
      <main>
        <%= yield %>
      </main>
      
      <aside class="sidebar">
        <p>Conteúdo regular da sidebar</p>
        <div class="sidebar-especifica">
          <%= yield :sidebar %>
        </div>
      </aside>
    </div>
  </body>
</html>

O template individual pode definir conteúdo específico para diferentes seções:

<% @titulo = "Minha Página Especializada" %>

<% content_for(:head) do %>
  <meta name="description" content="Página específica para SEO">
<% end %>

<% content_for(:sidebar) do %>
  <ul>
    <li>Menu específico da página</li>
    <li>Item dinâmico: <%= @dados_dinamicos %></li>
  </ul>
<% end %>

<p>Aqui está o conteúdo regular que aparecerá na página renderizada pelo template</p>

Partials com Coleções

Partials são especialmente poderosos quando trabalham com coleções de dados. Vamos ver um exemplo prático:

<!-- app/views/produtos/_produto.html.erb -->
<div class="produto">
  <div class="cabecalho-produto">
    <h3>
      <%= link_to produto.nome, produto %>
      <span class="contador">#<%= produto_counter + 1 %></span>
    </h3>
  </div>
  
  <div class="corpo-produto">
    <p><%= truncate(produto.descricao, length: 100) %></p>
    <div class="preco"><%= formatar_preco_brasileiro(produto.preco) %></div>
  </div>
</div>

O template principal renderiza a coleção com espaçador personalizado:

<!-- Renderização com coleção e espaçador -->
<div class="catalogo-produtos">
  <%= render(partial: "produto",
              collection: @lista_produtos,
              spacer_template: "divisor") %>
</div>

<!-- Partial compartilhado -->
<%= render("shared/cabecalho", locals: {titulo: @artigo.titulo}) %>

Boas Práticas e Considerações de Performance

Para maximizar a eficiência e manutenibilidade do seu código Action View, considere estas práticas essenciais:

  • Minimize lógica nas views: Mantenha templates focados na apresentação, delegando lógica complexa para helpers ou modelos.
  • Use partials estrategicamente: Quebre views grandes em partials reutilizáveis, especialmente para componentes repetidos.
  • Aproveite helpers integrados: O Rails oferece helpers otimizados para formatação, links e internacionalização.
  • Organize layouts hierarquicamente: Use layouts específicos de controller quando necessário, mantendo um layout de aplicação comum.
  • Teste helpers personalizados: Helpers são fáceis de testar isoladamente, ao contrário de código embarcado em views.

Conclusão

Action View oferece um ecossistema completo para construção de interfaces robustas e maintíveis. Desde templates básicos até sistemas complexos de layouts e partials, passando por formulários avançados e helpers personalizados, dominamos as ferramentas essenciais para criar aplicações Rails profissionais. A arquitetura MVC do Rails brilha especialmente na camada de view, onde a separação clara de responsabilidades e as convenções inteligentes aceleram significativamente o desenvolvimento.

Com este conhecimento sólido de Action View, você está preparado para construir interfaces de usuário elegantes que não apenas funcionam perfeitamente, mas também são fáceis de manter e evoluir ao longo do tempo.

Comentários (0)

Nenhum comentário:

Postar um comentário