Blog do Urubatan
msgbartop
Desenvolvedor, Palestrante, Escritor, Nerd Assumido e Pai do Marcus :D
msgbarbottom

16 Jan 08 Escrevendo plugins para o Rails – dicas e truques – plugins com view helpers

Uma das coisas mais legais no Rails[bb] é o suporte a Plugins …
O Ruby On Rails em si já é um excelente framework, mas a combinação dos Plugins do Rails com as classes abertas do Ruby é uma combinação explosiva!
Esta combinação é o que permite a criação de “tags” customizadas para utilizar nas suas aplicações RoR nas views e nos layouts.
E é realmente fácil de criar estes “view helpers” no Rails.

A forma padrão (sem plugins) de se criar estas “tags” é simplesmente criar um método em uma das classes Helper (as que ficam em app/helpers), por exemplo, se todos os forms na sua aplicação ficam dentro de tabelas, com uma coluna para o label e uma para o campo real, você pode criar um método helper para diminuir bastante a quantidade de código a ser digitada seguindo estes passos:

  1. rails plugins101
  2. cd plugins101
  3. ./script/generate scaffold example name:string url:string

O formulário padrão, bastante simples e feio, para o model “Example” que criamos, nesta aplicação seria algo parecido com:

1
2
3
4
5
6
7
<% form_for(@example) do |f| %>
  <table>
    <tr><td><label for="example_name">Name</label></td><td><%= f.text_field :name %></td></tr>
    <tr><td><label for="example_name">Url</label></td><td><%= f.text_field :url %></td></tr>
    <tr><td colspan="2"><%= f.submit "Update" %></td></tr>
  </table>
<% end %>

mas se editarmos o arquivo app/helpers/application_helper.rb e adicionarmos o seguinte método:

1
2
3
   def textfield label, object, property, options = {}
    %Q{<tr><td><label for="#{object.to_s}_#{property.to_s}">#{label}</label></td><td>#{text_field object, property, options}</td></tr>}
  end

o código da view ficaria muito mais simples como podemos ver abaixo.

1
2
3
4
5
6
7
<% form_for(@example) do |f| %>
  <table>
    <%= textfield "Name", :example, :name %>
    <%= textfield "Url", :example, :url %>
    <tr><td colspan="2"><%= f.submit "Update" %></td></tr>
  </table>
<% end %>

Se você pensar apenas neste pequeno formulário, pode parecer muita complicação para pouca coisa, mas pensando na aplicação inteira isto poupa bastante trabalho :D

Agora pensando um pouco maior, imagine que este padrão de layout (bem feio por sinal) que eu defini para esta aplicação, seja o padrão de todas as aplicações de toda a empresa!

e todos os desenvolvedores estão trabalhando da primeira forma que eu descrevi, codificando o HTML direto em todas as páginas.
Um belo dia, um designer novo, contratado pelo dono da empresa, diz que em todos os TR de todos os forms, é necessário adicionar uma classe CSS.
Nesta situação, o negócio é sentar e chorar …

Mas se você escolheu trabalhar da segunda forma, utilizando um helper, no máximo você precisara alterar uma linha de código por aplicação!
Você pode se considerar um herói! Certo?

Mas considere a opção de você ser ainda mais esperto do que isto! Que tal criar um plugin que vai conter estas tags para facilitar o trabalho, e utilizar este plugin em todas as aplicações da empresa?
Desta forma você precisaria alterar apenas uma linha de código, testar apenas uma vez, e todas as aplicações da empresa ja estariam corrigidas!

E como sempre, com o Rails, esta é uma tarefa muito fácil de ser completada :D
Apenas siga estes passos simples:

  1. ./script/generate plugin life_saver
  2. Edite o arquivo vendor/plugins/life_saver/lib/life_saver.rb e adicione o seguinte código nele:
    1
    2
    3
    4
    5
    6
    
    # LifeSaver
    module LifeSaver
      def textfield label, object, property, options = {}
        %Q{<tr><td><label for=#{object.to_s}_#{property.to_s}>#{label}</label></td><td>#{text_field object, property, options}</td></tr>}
      end
    end
  3. Edite o arquivo vendor/plugins/life_saver/init.rb e inclua o seguinte código:
    1
    2
    
    # Include hook code here
    ActionView::Base.send :include, LifeSaver
  4. Remova o método helper que adicionamos no arquivo app/helpers/application_helper.rb

Ok, você acabou de criar o seu primeiro plugin para o Rails[bb]!
E sim, o código é exatamente o mesmo utilizado no application_helper.rb, o único truque esta no init.rb, aquela linha de código, inclui todos os métodos do module “LifeSaver” na classe base de todas as views do Rails, a ActionView::Base.

Agora, se você escolheu esta terceira opção, va falar com o seu chefe, conte uma historia parecida com a que eu contei aqui, e peça um aumento, por que você merece, você acabou de poupar diversas horas de trabalho de umas 3 pessoas pelo menos :D

Espero que este pequeno passo a passo ajude alguem :D

Este é o primeiro post de uma série sobre escrita de plugins para RoR, o próximo vai ser sobre testes unitários para o código dos seus plugins, o terceiro vai falar de plugins com generators, e o quarto vocês vão ter que voltar aqui para descobrir sobre o que vai ser :D

Você gostou deste post? Compartilhe:
Se você gostou deste post, talvez você queira assinar o feed RSS! Você também pode me seguir no Twitter.

Tags: , , , , ,

Reader's Comments

  1. |

    Eu estou criando uma aplicação padrão para começar cada projeto. assim eu não perco mto tempo com models e views padrões em todos eles….

    Será que seria mais interessante fazer isso por plugins ? Vou dar uma estudada..

    E no aguardo para os próximos artigos.

    []s

  2. |

    sim, é mais interessante fazer isto por plugins, pois da forma como você esta fazendo, caso encontre um bug ou seja necessária alguma alteração você tera que alterar em diversos lugares, com certeza ira esquecer algum e provavelmente tera muitos problemas com isto.

    Esta má pratica também é conhecida como Copy & Paste anti pattern.

  3. |

    Legal o artigo. O exemplo citado seria comparabel mais ou menos com os macros do Freemarker por exemplo?

  4. |

    não exatamente, as macros são apenas texto, dentro destes helpers é possível chamar qualquer código Ruby e acessar qualquer parte da aplicação :D
    este exemplo básico é bem parecido, mas você vai ver a diferença melhor nos próximos posts da série sobre plugins :D

  5. |

    E aí Urubatan, tudo bem? Parabéns pelo post. Minha dúvida é se as modificações promovidas, por exemplo no LifeSaver, não passariam a impossibilitar a futuras atualização das bibliotecas ou do Rails para uma nova versão? Por exemplo, digamos que modificastes o LifeSaver, o que acontece quando quiseres atualizá-lo para nova versão?
    Falou, um abraço!

  6. |

    Caro Urubatan, qual ferramenta você utiliza para desenvolver em Ruby (e RoR)???

  7. |

    Fabiano …
    Este plugin pode ser por exemplo, empacotado separado de qualquer aplicação, e no caso de utilização de subversion, basta fazer a ligação com um svn:external, desta forma o plugin estaria sempre atualizado …

    Joel, estou utilizando o VIM :D

  8. |

    Urubatan,
    Muito bom esse artigo, nesse caso você demonstrou um exemplo utilizando um texfield, para as outras tags como textarea, selects e combos, funcionaria da mesma forma?

    Abraço,

  9. |

    Sim Arthur, exatamente igual …
    a idéia básica é que o método helper precisa devolver uma String …

  10. |

    Próximo exemplo podia rolar um plugin com migration,controller,views
    ia ser bem interessante
    :D

  11. |

    Clovis, este vai ser o último exemplo, pois é preciso utilizer engines para ter controllers dentro de um plugin, mas o próximo vai falar de generators e migration :D

  12. |

    [...] Artigo do Urubatan ensinando a criar plugins [...]

  13. |

    Olá,

    Ótima dica! Grande parte dos meus helpers agora viram plugins :-)

  14. |

    [...] a seqüencia que eu iniciei aqui, mas alterando a ordem proposta, Vamos conversar um pouco sobre os Geradores de código do [...]

  15. |

    [...] seus formulários no Rails By fernandoluizao A um ano atrás, o Urubatan escreveu um artigo sobre como diminuir a repetição nas views e padronizar formulários. A abordagem dele foi [...]