edge
Mais em rubyonrails.org: Mais Ruby on Rails

Visão Geral do Action View

Após ler este guia, você saberá:

1 O que é o Action View?

No Rails, as solicitações da web são tratadas pelo Action Controller e pelo Action View. Normalmente, o Action Controller se preocupa em se comunicar com o banco de dados e realizar ações CRUD quando necessário. O Action View é responsável por compilar a resposta.

Os templates do Action View são escritos usando Ruby embutido em tags misturadas com HTML. Para evitar poluir os templates com código repetitivo, várias classes auxiliares fornecem comportamentos comuns para formulários, datas e strings. Também é fácil adicionar novos auxiliares à sua aplicação à medida que ela evolui.

NOTA: Alguns recursos do Action View estão relacionados ao Active Record, mas isso não significa que o Action View depende do Active Record. O Action View é um pacote independente que pode ser usado com qualquer tipo de biblioteca Ruby.

2 Usando o Action View com o Rails

Para cada controlador, há um diretório associado no diretório app/views que contém os arquivos de template que compõem as views associadas a esse controlador. Esses arquivos são usados para exibir a view resultante de cada ação do controlador.

Vamos dar uma olhada no que o Rails faz por padrão ao criar um novo recurso usando o gerador de scaffold:

$ bin/rails generate scaffold article
      [...]
      invoke  scaffold_controller
      create    app/controllers/articles_controller.rb
      invoke    erb
      create      app/views/articles
      create      app/views/articles/index.html.erb
      create      app/views/articles/edit.html.erb
      create      app/views/articles/show.html.erb
      create      app/views/articles/new.html.erb
      create      app/views/articles/_form.html.erb
      [...]

Existe uma convenção de nomenclatura para as views no Rails. Normalmente, as views compartilham seu nome com a ação do controlador associada, como você pode ver acima. Por exemplo, a ação do controlador index do articles_controller.rb usará o arquivo de view index.html.erb no diretório app/views/articles. O HTML completo retornado para o cliente é composto por uma combinação deste arquivo ERB, um template de layout que o envolve e todos os partials que a view pode referenciar. Neste guia, você encontrará uma documentação mais detalhada sobre cada um desses três componentes.

Como mencionado, a saída HTML final é uma composição de três elementos do Rails: Templates, Partials e Layouts. Abaixo está uma breve visão geral de cada um deles.

3 Templates

Os templates do Action View podem ser escritos de várias maneiras. Se o arquivo de template tiver a extensão .erb, ele usará uma mistura de ERB (Embedded Ruby) e HTML. Se o arquivo de template tiver a extensão .builder, será usado a biblioteca Builder::XmlMarkup.

O Rails suporta vários sistemas de templates e usa uma extensão de arquivo para distingui-los. Por exemplo, um arquivo HTML usando o sistema de template ERB terá .html.erb como extensão de arquivo.

3.1 ERB

Dentro de um template ERB, código Ruby pode ser incluído usando as tags <% %> e <%= %> . As tags <% %> são usadas para executar código Ruby que não retorna nada, como condições, loops ou blocos, e as tags <%= %> são usadas quando você deseja exibir uma saída.

Considere o seguinte loop para nomes:

<h1>Nomes de todas as pessoas</h1>
<% @people.each do |person| %>
  Nome: <%= person.name %><br>
<% end %>

O loop é configurado usando tags de incorporação regulares (<% %>) e o nome é inserido usando as tags de incorporação de saída (<%= %>). Observe que isso não é apenas uma sugestão de uso: funções regulares de saída como print e puts não serão renderizadas na view com templates ERB. Portanto, isso estaria errado:

<%# ERRADO %>
Oi, Sr. <% puts "Frodo" %>

Para suprimir espaços em branco no início e no final, você pode usar <%- -%> alternadamente com <% e %>.

3.2 Builder

Os templates do Builder são uma alternativa mais programática ao ERB. Eles são especialmente úteis para gerar conteúdo XML. Um objeto XmlMarkup chamado xml é automaticamente disponibilizado para templates com a extensão .builder.

Aqui estão alguns exemplos básicos:

xml.em("enfatizado")
xml.em { xml.b("enfatizado e negrito") }
xml.a("Um link", "href" => "https://rubyonrails.org")
xml.target("name" => "compilar", "option" => "rápido")

que produziria:

<em>enfatizado</em>
<em><b>enfatizado e negrito</b></em>
<a href="https://rubyonrails.org">Um link</a>
<target option="rápido" name="compilar" />

Qualquer método com um bloco será tratado como uma tag de marcação XML com marcação aninhada no bloco. Por exemplo, o seguinte: ruby xml.div do xml.h1(@person.name) xml.p(@person.bio) end

produziria algo como:

<div>
  <h1>David Heinemeier Hansson</h1>
  <p>Um produto do Design Dinamarquês durante o Inverno de '79...</p>
</div>

Abaixo está um exemplo completo de RSS realmente usado no Basecamp:

xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
  xml.channel do
    xml.title(@feed_title)
    xml.link(@url)
    xml.description "Basecamp: Itens recentes"
    xml.language "en-us"
    xml.ttl "40"

    for item in @recent_items
      xml.item do
        xml.title(item_title(item))
        xml.description(item_description(item)) if item_description(item)
        xml.pubDate(item_pubDate(item))
        xml.guid(@person.firm.account.url + @recent_items.url(item))
        xml.link(@person.firm.account.url + @recent_items.url(item))
        xml.tag!("dc:creator", item.author_name) if item_has_creator?(item)
      end
    end
  end
end

3.3 Jbuilder

Jbuilder é uma gem mantida pela equipe do Rails e incluída no Gemfile padrão do Rails. É semelhante ao Builder, mas é usado para gerar JSON, em vez de XML.

Se você não tiver, pode adicionar o seguinte ao seu Gemfile:

gem 'jbuilder'

Um objeto Jbuilder chamado json é automaticamente disponibilizado para templates com a extensão .jbuilder.

Aqui está um exemplo básico:

json.name("Alex")
json.email("[email protected]")

produziria:

{
  "name": "Alex",
  "email": "[email protected]"
}

Consulte a documentação do Jbuilder para obter mais exemplos e informações.

3.4 Cache de Templates

Por padrão, o Rails irá compilar cada template em um método para renderizá-lo. No ambiente de desenvolvimento, quando você altera um template, o Rails verifica a data de modificação do arquivo e o recompila.

4 Partials

Partial templates - geralmente chamados de "partials" - são outro recurso para dividir o processo de renderização em partes mais gerenciáveis. Com partials, você pode extrair trechos de código de seus templates para arquivos separados e também reutilizá-los em seus templates.

4.1 Renderizando Partials

Para renderizar um partial como parte de uma view, você usa o método render dentro da view:

<%= render "menu" %>

Isso irá renderizar um arquivo chamado _menu.html.erb naquele ponto dentro da view que está sendo renderizada. Observe o caractere de sublinhado inicial: os partials são nomeados com um sublinhado inicial para distingui-los das views regulares, mesmo que sejam referenciados sem o sublinhado. Isso é válido mesmo quando você está puxando um partial de outra pasta:

<%= render "shared/menu" %>

Esse código irá puxar o partial de app/views/shared/_menu.html.erb.

4.2 Usando Partials para Simplificar Views

Uma maneira de usar partials é tratá-los como equivalentes a sub-rotinas; uma maneira de mover detalhes de uma view para que você possa entender o que está acontecendo com mais facilidade. Por exemplo, você pode ter uma view que se parece com isso:

<%= render "shared/ad_banner" %>

<h1>Produtos</h1>

<p>Aqui estão alguns de nossos ótimos produtos:</p>
<% @products.each do |product| %>
  <%= render partial: "product", locals: { product: product } %>
<% end %>

<%= render "shared/footer" %>

Aqui, os partials _ad_banner.html.erb e _footer.html.erb podem conter conteúdo compartilhado entre muitas páginas em sua aplicação. Você não precisa ver os detalhes dessas seções quando está se concentrando em uma página específica.

4.3 render sem as opções partial e locals

No exemplo acima, render recebe 2 opções: partial e locals. Mas se essas são as únicas opções que você deseja passar, você pode pular o uso dessas opções. Por exemplo, em vez de:

<%= render partial: "product", locals: { product: @product } %>

Você também pode fazer:

<%= render "product", product: @product %>

4.4 As opções as e object

Por padrão, ActionView::Partials::PartialRenderer tem seu objeto em uma variável local com o mesmo nome do template. Então, dado:

<%= render partial: "product" %>

dentro do partial _product, teremos @product na variável local product, como se tivéssemos escrito:

<%= render partial: "product", locals: { product: @product } %>

A opção object pode ser usada para especificar diretamente qual objeto é renderizado no partial; útil quando o objeto do template está em outro lugar (por exemplo, em uma variável de instância diferente ou em uma variável local).

Por exemplo, em vez de:

<%= render partial: "product", locals: { product: @item } %>

fariamos:

<%= render partial: "product", object: @item %>

Com a opção as, podemos especificar um nome diferente para a variável local mencionada. Por exemplo, se quisermos que seja item em vez de product, faríamos:

<%= render partial: "product", object: @item, as: "item" %>

Isso é equivalente a erb <%= render partial: "product", locals: { item: @item } %>

4.5 Renderizando Coleções

Comumente, um template precisará iterar sobre uma coleção e renderizar um sub-template para cada um dos elementos. Esse padrão foi implementado como um único método que aceita um array e renderiza um partial para cada um dos elementos do array.

Então, esse exemplo para renderizar todos os produtos:

<% @products.each do |product| %>
  <%= render partial: "product", locals: { product: product } %>
<% end %>

pode ser reescrito em uma única linha:

<%= render partial: "product", collection: @products %>

Quando um partial é chamado com uma coleção, as instâncias individuais do partial têm acesso ao membro da coleção que está sendo renderizado através de uma variável com o nome do partial. Nesse caso, o partial é _product, e dentro dele, você pode se referir a product para obter o membro da coleção que está sendo renderizado.

Você pode usar uma sintaxe abreviada para renderizar coleções. Supondo que @products seja uma coleção de instâncias de Product, você pode simplesmente escrever o seguinte para produzir o mesmo resultado:

<%= render @products %>

O Rails determina o nome do partial a ser usado olhando para o nome do modelo na coleção, Product neste caso. Na verdade, você pode até mesmo renderizar uma coleção composta por instâncias de modelos diferentes usando essa sintaxe abreviada, e o Rails escolherá o partial adequado para cada membro da coleção.

4.6 Templates de Espaçamento

Você também pode especificar um segundo partial para ser renderizado entre as instâncias do partial principal usando a opção :spacer_template:

<%= render partial: @products, spacer_template: "product_ruler" %>

O Rails irá renderizar o partial _product_ruler (sem dados passados para ele) entre cada par de partials _product.

4.7 Locais Estritos

Por padrão, os templates aceitam qualquer locals como argumentos de palavra-chave. Para definir quais locals um template aceita, adicione um comentário mágico locals:

<%# locals: (message:) -%>
<%= message %>

Valores padrão também podem ser fornecidos:

<%# locals: (message: "Olá, mundo!") -%>
<%= message %>

Ou locals podem ser desativados completamente:

<%# locals: () %>

5 Layouts

Layouts podem ser usados para renderizar um template de visualização comum em torno dos resultados das ações do controlador do Rails. Tipicamente, uma aplicação Rails terá alguns layouts nos quais as páginas serão renderizadas. Por exemplo, um site pode ter um layout para um usuário logado e outro para o lado de marketing ou vendas do site. O layout para o usuário logado pode incluir navegação de alto nível que deve estar presente em várias ações do controlador. O layout de vendas para um aplicativo SaaS pode incluir navegação de alto nível para coisas como páginas "Preços" e "Fale Conosco". Você esperaria que cada layout tenha uma aparência e sensação diferentes. Você pode ler mais sobre layouts em mais detalhes no guia Layouts e Renderização no Rails.

5.1 Layouts Parciais

Partials podem ter seus próprios layouts aplicados a eles. Esses layouts são diferentes daqueles aplicados a uma ação do controlador, mas funcionam de maneira semelhante.

Digamos que estamos exibindo um artigo em uma página que deve ser envolvido em uma div para fins de exibição. Primeiro, vamos criar um novo Article:

Article.create(body: 'Layouts Parciais são legais!')

No template show, vamos renderizar o partial _article envolvido no layout box:

articles/show.html.erb

<%= render partial: 'article', layout: 'box', locals: { article: @article } %>

O layout box simplesmente envolve o partial _article em uma div:

articles/_box.html.erb

<div class='box'>
  <%= yield %>
</div>

Observe que o layout parcial tem acesso à variável local article que foi passada para a chamada render. No entanto, ao contrário dos layouts em toda a aplicação, os layouts parciais ainda têm o prefixo de sublinhado.

Você também pode renderizar um bloco de código dentro de um layout parcial em vez de chamar yield. Por exemplo, se não tivéssemos o partial _article, poderíamos fazer isso em vez disso:

articles/show.html.erb

<% render(layout: 'box', locals: { article: @article }) do %>
  <div>
    <p><%= article.body %></p>
  </div>
<% end %>

Supondo que usemos o mesmo partial _box acima, isso produziria a mesma saída que o exemplo anterior.

6 Caminhos de Visualização

Ao renderizar uma resposta, o controlador precisa resolver onde estão localizadas as diferentes visualizações. Por padrão, ele só procura dentro do diretório app/views. Podemos adicionar outros locais e dar-lhes uma certa precedência ao resolver caminhos usando os métodos prepend_view_path e append_view_path.

6.1 Prepend View Path

Isso pode ser útil, por exemplo, quando queremos colocar as visualizações dentro de um diretório diferente para subdomínios.

Podemos fazer isso usando:

prepend_view_path "app/views/#{request.subdomain}"

Então, o Action View irá procurar primeiro neste diretório ao resolver as visualizações.

6.2 Append View Path

Da mesma forma, podemos adicionar caminhos:

append_view_path "app/views/direct"

Isso irá adicionar app/views/direct ao final dos caminhos de pesquisa.

7 Helpers

O Rails fornece muitos métodos auxiliares para usar com o Action View. Estes incluem métodos para:

  • Formatação de datas, strings e números
  • Criação de links HTML para imagens, vídeos, folhas de estilo, etc...
  • Sanitização de conteúdo
  • Criação de formulários
  • Localização de conteúdo

Você pode aprender mais sobre os auxiliares no Guia de Auxiliares do Action View e no Guia de Auxiliares de Formulário do Action View.

8 Visualizações Localizadas

O Action View tem a capacidade de renderizar diferentes modelos dependendo da localidade atual.

Por exemplo, suponha que você tenha um ArticlesController com uma ação de exibição. Por padrão, chamar esta ação irá renderizar app/views/articles/show.html.erb. Mas se você definir I18n.locale = :de, então app/views/articles/show.de.html.erb será renderizado em seu lugar. Se o modelo localizado não estiver presente, a versão não decorada será usada. Isso significa que você não é obrigado a fornecer visualizações localizadas para todos os casos, mas elas serão preferidas e usadas se estiverem disponíveis.

Você pode usar a mesma técnica para localizar os arquivos de resgate em seu diretório público. Por exemplo, definir I18n.locale = :de e criar public/500.de.html e public/404.de.html permitiria que você tivesse páginas de resgate localizadas.

Como o Rails não restringe os símbolos que você usa para definir I18n.locale, você pode aproveitar esse sistema para exibir conteúdo diferente dependendo do que quiser. Por exemplo, suponha que você tenha alguns usuários "especialistas" que devem ver páginas diferentes dos usuários "normais". Você poderia adicionar o seguinte em app/controllers/application_controller.rb:

before_action :set_expert_locale

def set_expert_locale
  I18n.locale = :expert if current_user.expert?
end

Então você poderia criar visualizações especiais como app/views/articles/show.expert.html.erb que só seriam exibidas para usuários especialistas.

Você pode ler mais sobre a API de Internacionalização (I18n) do Rails aqui.

Feedback

Você é incentivado a ajudar a melhorar a qualidade deste guia.

Por favor, contribua se encontrar algum erro de digitação ou factual. Para começar, você pode ler nossa contribuição à documentação seção.

Você também pode encontrar conteúdo incompleto ou desatualizado. Por favor, adicione qualquer documentação ausente para o principal. Certifique-se de verificar Guias Edge primeiro para verificar se os problemas já foram corrigidos ou não no branch principal. Verifique as Diretrizes dos Guias do Ruby on Rails para estilo e convenções.

Se por algum motivo você encontrar algo para corrigir, mas não puder corrigi-lo você mesmo, por favor abra uma issue.

E por último, mas não menos importante, qualquer tipo de discussão sobre a documentação do Ruby on Rails é muito bem-vinda no Fórum oficial do Ruby on Rails.