HE:labs

Postado por Rodrigo Pinto em 28/06/2013

Usando decorators nos models Rails de forma intrusiva

Muito já se falou sobre decorators nos últimos tempos, até mesmo por aqui. Melhorar a legibilidade e remover lógica das views de uma aplicação é um assunto que me interessa já faz algum tempo. Nesse post falarei sobre a alternativa que, no meu ponto de vista, preencheu a lacuna do problema decorators de views no rails .

Há diversas formas de implementar um decorator e já existem inúmeras gems que auxiliam neste trabalho, como o simple_presenter e o draper. O que me incomodava em todas as diversas soluções existentes, é o desenvolvedor ter que passar o objeto ou a coleção de objetos para a classe do decorator para que fosse decorado. Pensando no caso de uma action, ela teria de ser alterada, como pode ser visto no exemplo a seguir:

1 # any controller...
2 def index
3   @users = UserPresenter.map(User.all) # simple presenter
4   @articles = ArticleDecorator.decorate_collection(Article.all) # draper
5 end

Esse tipo de solução sempre me incomodou, e eu mantive minha busca por alguma que funcionasse de forma intrusiva, sem que fosse preciso modificar a chamada na action. E esta solução existe, chama-se active_decorator.

O active_decorator injeta automaticamente o decorator em um model, ou em uma coleção de models ou uma instância do ActiveRecord::Relation a partir de um controller ou renderizando uma view com :collection ou :object ou :local. Sendo assim, não é preciso alterar nenhuma chamada no seu controller.

Vamos ver o exemplo anterior usando o active decorator.

1 # any controller...
2 def index
3   @users = User.all
4   @articles = Article.all
5 end

Existindo um UserDecorator e um ArticleDecorator, os objetos das coleções serão automaticamente decorados quando forem ser usados nas views.

Veja um exemplo mais completo:

 1 # any controller...
 2 def index
 3   @user = current_user
 4   @articles = current_user.articles
 5 end
 6 
 7 # user decorator
 8 module UserDecorator
 9 
10   def full_name
11     "#{first_name}-#{last_name}"
12   end
13 
14 end
15 
16 # article decorator
17 module ArticleDecorator
18 
19   def link_to_publish
20     if published?
21       "On air!"
22     else
23       link_to "Publish", publish_article_path(self)
24     end
25   end
26 end
 1 # app/views/articles/index.erb
 2 
 3 Olá <%= @user.full_name %>
 4 
 5 <ul>
 6 <% @articles.each do |article| %>
 7   <li>
 8     <%= article.title %>
 9     <%= article.link_to_publish %>
10   </li>
11 <% end %>
12 </ul>

O active decorator é totalmente "plugável" a uma aplicação existente o que reduz bastante o esforço de implementação de decorators, facilitando a implementação gradual.

Abraços, Rodrigo Pinto.

Comentários
Included file post/disqus_thread.html not found in _includes directory