[PT-BR] Organizando flash messages no Phoenix
Tags: phoenix, elixir, myelixirstatus
Published: 2020-02-16 18:30:27

---
title: [PT-BR] Organizando flash messages no Phoenix
published: true
description: Para você quer quer organizar as flash messages no Phoenix
tags: phoenix, elixir, myelixirstatus
---

Bom, comecei a fazer um sistema para entender melhor como funciona [Elixir](https://elixir-lang.org/) e aprender sobre o [Phoenix](https://www.phoenixframework.org/).

O [Phoenix](https://www.phoenixframework.org/) é um framework para [Elixir](https://elixir-lang.org/), assim como o [Rails](https://rubyonrails.org/) é um framework para o [Ruby](https://www.ruby-lang.org/en/), ele tem como missão ser um framework produtivo e que não compromete a velocidade ou a capacidade de manutenção.

Sem mais delongas, decidi criar um CRUD simples em [Elixir](https://elixir-lang.org/) para eu registrar os livros que eu já li, utilizei os seguintes comandos:

```shell
# Cria a aplicação.
$ mix phx.new booklistx

# Entra no projeto criado
cd booklistsx

# Gerador do CRUD (estilo scaffold do rails)
mix phx.gen.html Books Book books title:string

# Cria o banco e cria a tabela de books
mix ecto.create
mix ecto.migrate
```

Defini como root da aplicação ser a listagem de livros.

```elixir
# lib/booklistx_web/router.ex

defmodule BooklistxWeb.Router do
  use BooklistxWeb, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", BooklistxWeb do
    pipe_through :browser

    # get "/", PageController, :index # <- Comentei essa linha!
    resources "/", BooksController    # <- Adicionei essa linha!
  end

  # Other scopes may use custom stacks.
  # scope "/api", BooklistxWeb do
  #   pipe_through :api
  # end
end
```

Executei o comando para iniciar a aplicação.

```
$ mix phx.server
```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/hu9jspp48viwq06dpf2g.png)

Após isso estava pronto eu já podia adicionar livros e remover livros, foi ai que quando criei um livro mostrava uma flash message.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/blagx209x29io841dqom.png)

Utilizei o inspetor do browser para ver como era o html.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/9s99k9qrskxkg8fy1ek0.png)

Ví que o html sempre vinha com as tags html de flash message.

```html
<p class="alert alert-info" role="alert">Book updated successfully.</p>
<p class="alert alert-danger" role="alert"></p>
```

Tem apenas um truque simples de css para não mostrar nada caso não houver nenhum conteúdo na tag.

```css
/* assets/css/phoenix.css */

.alert:empty {
  display: none;
}
```

Por padrão o arquivo vem assim, carregando as tags de alert mesmo que não tenha nenhuma flash message.

```eex
# lib/booklistx_web/layout/app.html.exx

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Booklistx · Phoenix Framework</title>

    <link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
    <%= csrf_meta_tag() %>
  </head>

  <body>
    <header>
      <section class="container">
        <nav role="navigation">
          <ul>
            <li><a href="https://hexdocs.pm/phoenix/overview.html">Get Started</a></li>
          </ul>
        </nav>
        <a href="https://phoenixframework.org/" class="phx-logo">
          <img src="<%= Routes.static_path(@conn, "/images/phoenix.png") %>" alt="Phoenix Framework Logo"/>
        </a>
      </section>
    </header>
    <main role="main" class="container">
#->   <p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
#->   <p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>

      <%= render @view_module, @view_template, assigns %>
    </main>
    <script type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
  </body>
</html>
```

Isso estava me incomodando, pesquisei sobre como funciona e encontrei em uma issue sugerindo para utilizar da seguinte forma.

```eex
# lib/booklistx_web/layout/app.html.exx
...
<%= if info = get_flash(@conn, :info) do %>
  <p class="alert alert-info" role="alert"><%= info %></p>
<% end %>

<%= if error = get_flash(@conn, :error) do %>
  <p class="alert alert-danger" role="alert"><%= error %></p>
<% end %>
...
```

Ele só vai mostrar agora caso tenha alguma flash message, porem essas variaveis no meio do código não ficou legal `info` e `error`.

Decidi fazer algo parecido com o que já fiz no Rails.

Acredito que deve ter várias outras formas de resolver isso e que deve ser melhor, porem essa foi a que eu mais gostei porque é simples e utiliza os conceitos que eu venho estudando.

Criei os seguintes arquivos:

```shell
# Cria o arquivo shared_view
$ touch lib/booklistx_web/shared_view.ex
# Cria a pasta shared
$ mkdir lib/booklistx_web/templates/shared
# Cria o arquivo _flash_message.html.exx
$ touch lib/booklistx_web/templates/shared/_flash_message.html.eex
```

```elixir
# lib/booklistx_web/shared_view.ex

defmodule BooklistxWeb.SharedView do
  use BooklistxWeb, :view
  import BooklistxWeb.Router.Helpers

  def show_flash_message(conn) do
    conn
    |> get_flash
    |> flash_message
  end

  def flash_message(%{"info" => message}) do
    render "_flash_message.html", class: "primary", message: message
  end

  def flash_message(%{"error" => message}) do
    render "_flash_message.html", class: "danger", message: message
  end

  def flash_message(_), do: nil
end
```

Aqui eu estou utilizando coisas que eu aprendi como pipe e pipeline no método `show_flash_message` e pattern matching para o método `flash_message`.

Já a partial ficou da seguinte forma.

```eex
# lib/booklistx_web/templates/shared/_flash_message.html.eex

<p class="alert alert-<%= @class %>" role="alert">
  <%= @message %>
</p>
```

O nosso layout ficou da seguinte forma:

```eex
# lib/booklistx_web/layout/app.html.exx

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Booklistx · Phoenix Framework</title>

    <link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
    <%= csrf_meta_tag() %>
  </head>

  <body>
    <header>
      <section class="container">
        <nav role="navigation">
          <ul>
            <li><a href="https://hexdocs.pm/phoenix/overview.html">Get Started</a></li>
          </ul>
        </nav>
        <a href="https://phoenixframework.org/" class="phx-logo">
          <img src="<%= Routes.static_path(@conn, "/images/phoenix.png") %>" alt="Phoenix Framework Logo"/>
        </a>
      </section>
    </header>
    <main role="main" class="container">
      <%= BooklistxWeb.SharedView.show_flash_message(@conn) %>

      <%= render @view_module, @view_template, assigns %>
    </main>
    <script type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
  </body>
</html>
```

### Conclusão

No meu ponto de vista, ficou bem melhor do que utilizarmos as variáveis (`info` e `error`) e aqueles IF direto no layout, acredito que deve ter soluções melhores, mas essa foi a que eu consegui fazer e mais me agradou. Consegui colocar em pratica algumas coisas que aprendi como o pipe, pipeline e pattern matching.

Vou deixar o link desse código que eu fiz no github.

[https://github.com/guilhermeyo/booklistx](https://github.com/guilhermeyo/booklistx)

Fique a vontade para deixar um feedback e melhorias que posso realizar.

---

### Referências

[#23: Partial Templates with Phoenix](https://elixircasts.io/partial-templates-with-phoenix)
[Elixir forum - Check for error and info alert in Phoenix](https://elixirforum.com/t/check-for-error-and-info-alert-in-phoenix/1984/)
[Issue phoenixframework - Add has_flash? functions. #1757](https://github.com/phoenixframework/phoenix/issues/1757)