A pior maneira de lidar com sessoes com Phoenix Liveview.
Tags: elixir, phoenix, beam, tailwindcss
Published: 2022-07-05 21:53:07

# Saudacao

Seja muito bem vindo, seja muito bem vinda ao #FullstackElxpro


Aqui nós discutimos as estratégias e dicas de sua jornada de aprendizado em Elixir. Isso é do zero até a sua primeira vaga como desenvolvedor elixir

**Do you want to learn Elixir in three months? https://elxpro.com/sell**

Eu sou o Gustavo e o tema de hoje é: **A pior maneira de lidar com sessoes com Phoenix Liveview.**

_ps: Voce pode acompanhar o artigo com o video

_Quer aprender mais sobre elixir em um canal do Telegram?_
https://elxpro.com/elxcrew-org-yt-descr


# O que é?

Sessao basicamente e algo temporareo em uma aplicacao. Nao e nada mais e nada menos que isso. 

Porem em Elixir, Phoenix e Liveview (principalmente a parte web) ha diversas maneiras de trabalhar com sessao.  

Pode utilizar:

## [Plugs](https://hexdocs.pm/phoenix/plug.html)

Que e um middleware de conexao e atravez deste middleware persistir dados e ler dados em uma sessao. E ha diversos plugs para lidar com este middle, mas nao e o caso deste artigo


## [Phoenix Token
](https://hexdocs.pm/phoenix/Phoenix.Token.html)

E uma maneira de utilizar e guardar dados que expiram de maneira simples


## Liveview

Ha diversas maneiras como: session_storage, local_storage (desde que use hooks), live_session. E tu pode conferir todos os tipos de abordagem.

O que voce vai ver neste artigo e live_session e o porque utiliza-lo, pois ha diversas vantagens e abordagens que sao extremamente simples que vai fazer toda a diferenca na manutencao e legibilidade da aplicacao.


# Qual a Diferença entre **sessoes** e **live_session**?

A principal diferenca e que a sessao o foco maior e na conexao, trafegar dados persistidos na conexao. 

Agora no live_session voce consegue pegar os dados da _sessao_, incluir no **socket** e tambem consegue programar eventos genericos em sua pagina o que facilita muito para nao replicar codigo, em resumo e um middleware com super poderes. 




# Como foi que você descobriu isso?

A maneira como eu descobri, foi na leitura do upgrade do phoenix 1.5 para o 1.6. E quando apareceu **live_session** achava que nao tinha necessidade alguma. Porem em uma aplicacao que venho trabalhando tinha um header compartilhado usando uma pagina liveview dentro de outra pagina liveview. 

Se voce entende de processos, tinha um processo monitorando outro uma complexidade absurda para criar comunicao, exigia muito do time entender como **OTP, Elixir, Processos** funciona por debaixo dos panos e mesmo entendo tudo isso, e uma solucao (workaround) era tao verboso e complicado de manipular. 

Neste evento eu ja tinha trabalhado com **live_session** em outros projetos (fora da Empresa), e vi o quao poderoso e a quantidade de beneficios que o live_session traz para a nova versao do **Phoenix Liveview** atravez de uma conversa sobre decisoes de codigo eu apresentei a solucao e todos gostaram e a implementacao foi muito simples.  

_ps: (eu nao vou mostrar a solucao desenvolvida neste artigo, porem, no final, voce sera capaz de criar solucoes melhores do que eu implementei)_



# Por quê **live_session** é importante?

A grande importancia e a questao dos superpodeeres que sao faceis de utilizar. Um dos divisores de agua da versao 1.5 para a 1.6 foi o _live_session_ pois voce nao precisa escrever muito codigo, com poucas linhas voce vai conseguir interagir com o socket e incluir implementacoes e eventos, e principalmente criar regras de falhas. 

# Qual o maior benefício do **live_session**?

O maior beneficio e a questao de manipular um socket como uma sessao. 


# Você se lembra de alguma história em que isso foi importante pra você?

Como eu mensionei, a principal historia foi a questao de assinar informacoes no socket de maneira generica, sem ter que replicar codigos algo que desenvolvedores acha chato e realmente e. 

E a outra foi quando precisei trigar eventos de **handle_events, handle_infos, handle_params** sem precisar implementar em todas as paginas



# Como criar **live_sessions**?


Voce pode comecar entendendo o motivo. Algumas perguntas pode te ajudar:


- Eu preciso de compartilhar essa informacao com mais de 1 pagina?
- Esse evento precisa ser replicado em mais de uma pagina? 
- Preciso de criar alguma regra de negocio generalizada? 


Se a resposa for sim, o **[live_session](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.Router.html#live_session/3)** e a melhor opcao. 

Voce pode acomparnhar na imagem abaixo que foi preciso implementar somente algumas linhas de codigos e o livesession comeca a se comportar como um _middleware_


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dw10zivsq0roly4fvjvj.png)

Antes de comecar qualquer sessao o que o **live_session** vai fazer e chamar o modulo de permissao, verficiando o escopo (o que e um pattern matching mais do que incrivel)  e assinar novas informacoes no socket. 


 

```
defmodule LiveSessions.Permissions do
  import Phoenix.LiveView
  alias FoodOrder.Accounts
  alias FoodOrderWeb.Router.Helpers, as: Routes
  alias LiveSessions.CreateCart

  def on_mount(:user, _params, %{"user_token" => user_token}, socket) do
    assign_user(socket, :user, user_token)
  end

  def on_mount(:admin, _params, %{"user_token" => user_token}, socket) do
    assign_user(socket, :admin, user_token)
  end

  defp assign_user(socket, _, nil) do
    error_login(socket, "You must be logged in")
  end

  defp assign_user(socket, :user, user_token) do
    current_user = Accounts.get_user_by_session_token(user_token)
    cart_id = get_connect_params(socket)["cart_id"]

    socket =
      socket
      |> assign_new(:current_user, fn -> current_user end)
      |> CreateCart.execute(cart_id)

    {:cont, socket}
  end

  defp assign_user(socket, :admin, user_token) do
    user_token
    |> Accounts.get_user_by_session_token()
    |> return_socket(socket)
  end

  defp return_socket(%{role: role}, socket) when role != :ADMIN,
    do: error_login(socket, "You don`t have permissions to access this page")

  defp return_socket(current_user, socket),
    do: {:cont, assign_new(socket, :current_user, fn -> current_user end)}

  defp error_login(socket, message) do
    socket =
      socket
      |> put_flash(:error, message)
      |> redirect(to: Routes.main_path(socket, :index))

    {:halt, socket}
  end
end
```


# Finalizacao


Eu espero que eu tenha te ajudado no seu aprendizado, recomendo sempre visitar os videos do youtube, geralmente tem mais recursos. Um grande abraco!! 



Redes Sociais: 

- [Gustavo Oliveira](https://www.linkedin.com/in/gustavo-oliveira-642b23aa/)
- [Elxpro(linkedin)](https://www.linkedin.com/company/36977430)
- [Twiter](https://twitter.com/elx_pro)
- [ElxproBr](https://www.youtube.com/channel/UCl_BBK2sXZzQy_3ziNU7-XA)
- [Elxpro](https://www.youtube.com/channel/UCLzHBFuE6oxPdP6t9iqpGpQ)