Aplicando Decorators usando a gema Draper

Publicado por Marcus Caum no dia dev

decorators

Quando estamos começando a desenvolver, é normal adicionarmos algum tipo de lógica na view - seja para definir se uma div é exibida ou para tratar algum comportamento. Ao fazer isso, estamos aumentando o tamanho da nossa View e adicionando código que por vezes nem é usado, em uma aplicação robusta, este comportamento não escala. O Rails disponibiliza uma série de View Patterns para resolver esse tipo de problema, sendo um deles o uso de Decorators - normalmente recomendando quando precisamos exibir dados retirados de um Model. Neste post, vou demonstrar como realizar o uso desta prática de forma fácil e eficiente.

Let’s code!

Para começar, vamos montar um exemplo simples onde temos um Model com o nome Car e os atributos description, year e model definido no Model - onde constam ano e modelo do nosso carro. Partindo desta ideia, criei um exemplo simples abaixo que trás os dados presentes do nosso carro dentro de uma div.

1
2
3
4
5
6
7
8
9
10
#! app/views/car.html.erb

<html>
  <body>
    <div id="car">
      <div> <%= "#{@car.model} - #{@car.year} "%>"</div>
      <div> <%= @car.description %></div>
    </div>
  </body>
</html>

Here comes the Draper!

Podemos tratar isto com o uso de decorator e remover estas chamadas da view.

Para facilitar nosso processo, podemos utilizar a gem Draper. Com a gema, conseguimos criar dinamicamente uma classe decorator que irá trabalhar diretamente com o nosso Model.

Para utilizar a gema é simples, basta seguir os passos apresentado no Readme do repositório do Draper - que está bem feito, atualizado e de fácil execução. Vale dar um lida completa em toda a sua documentação, pois a mesma é bem completa e possui diversas configurações que facilitam ainda mais seu desenvolvimento. Neste exemplo, abordarei o básico, mostrando a principal função do Draper.

show me the code

Vamos criar decorator para nosso modelo Car, seguindo os passos do readme do Draper. Após rodarmos rails generate decorator Car, um decorator será gerado com a classe CarDecorator, esta é a classe onde iremos adicionar o tratamento que antes estava presente na nossa View. Criaremos um metódo que irá renderizar uma div. A sintaxe é bem fácil e lembra bastante a criação de um Helper. A diferença de um Helper é que este é aplicado à situações onde o tratamento previsto é utilizado em mais de um lugar e contexto. No exemplo desse post, iremos usar somente nesta View e com este Model.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#! app/decorators/car_decorator.rb

class CarDecorator < Draper::Decorator

  delegate_all

  def description
    h.content_tag('div', model.description)
  end

  def display_name
    h.content_tag('div', "#{model.model} - #{model.year}")
  end
end

Criamos dois metódos: um que cria uma div com a descrição do nosso carro e outro que cria uma div contendo o modelo e ano. Por se tratar de um View Pattern, conseguimos utilzar os metódos convencionais de um helper, como o content_tag. Note também que, em nosso decorator, usamos o delegate_all do Draper: com ele conseguimos ter acesso a todos os metódos presentes em no Model.

Após criar os metódos no decorator, iremos aplicá-lo na chamada do Model em nosso Controller. Uma das possibilidades ao se usar Draper é que temos um controle de quais chamadas queremos que sejam “decoradas”. Bastar adicionar um .decorate no final da chamada do Model no Controller. Com isso, temos a possibilidade de usar duas varíaveis @car: uma “decorada” e outra normal. Dessa forma, evitamos conflitos de metódos presentes em nosso Model que possuam o mesmo nome no decorator

1
2
3
4
5
6
7
8
#! app/controllers/car_controller.rb
class CarController  < ApplicationController

  def show
    @car = Car.find(params[:id])
    @decorated_car = Car.find(params[:id]).decorate
  end
end

Após implementar o Draper, passamos a exibir os dados do nosso carro de uma maneira mais limpa e correta, removendo a complexidade da View e tornando o código de mais fácil compreensão.

1
2
3
4
5
6
7
8
9
10
#! app/views/car.html.rb

<html>
  <body>
    <div id="car">
      <%= @decorated_car.display_name %>
      <%= @decorated_car.description %>
    </div>
  </body>
</html>

Após o uso conseguimos ter um controle maior dos campos criados e isolamos o tratamento, facilitando a manutenção e a aplicação de novos campos se necessário no futuro.

E você? Tem alguma dúvida ou história relacionada com Decorators? Poste nos comentários :)

Marcus Caum

Marcus Caum

Full Stack Developer

Comentários