Archive for September, 2009

Formulários com Formtastic

September 7th, 2009

Procurando uma alternativa para trabalhar com formulários no Rails, encontrei a gem Formtastic.

O projeto é mantido por Justin French e José Valim, além de outras pessoas que ajudaram no projeto. Todo o código fonte esta no Github.

Sem mais, vamos trabalhar =)

Preparando o ambiente

Para gerar os scaffolds e um layout básico vou usar a gem Nifty Generators do Ryan Bates.

Instalando a gem nifty-generators:

sudo gem install nifty-generators

Criado a aplicação:

Pensando em acelerar um pouco o processo, criei um template básico e vamos criar a aplicação usando ele!

rails formtastic -m http://gist.github.com/181560.txt
cd formtastic

Instalando a gem formtastic:

sudo gem install justinfrench-formtastic

Adicione no environment.rb:

# config/environment.rb
config.gem "justinfrench-formtastic", :version => "0.2.2", :lib => 'formtastic', :source  => 'http://gems.github.com'

Gerando um layout basicão:

script/generate nifty_layout

Pronto :)

Usando

Como minha criatividade não permite algo diferente, vamos trabalhar com Produtos e Categorias.

Gerando o scaffold para Categorias:

script/generate nifty_scaffold Category name:string status:boolean ! show

Rode as migrações:

rake db:migrate

Se olharmos o código do formulário criado, teremos algo como:

# app/views/categories/_form.html.erb
 
<% form_for @category do |f| %>
  <%= f.error_messages %>
  <p>
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.label :status %><br />
    <%= f.check_box :status %>
  </p>
  <p><%= f.submit "Submit" %></p>
<% end %>

Visualizando o formulário:

tela02

Ok Jésus! Você falou, falou, mas cade o Formtastic?

Até agora não fizemos nada com ele. Experimente trocar o código gerado pelo scaffold pelo código abaixo:

# app/views/categories/_form.html.erb
 
<% semantic_form_for @category do |form| %>
  <%= form.inputs %>
  <%= form.buttons %>
<% end %>

Somente isso? Vamos ver o formulário:

tela03

Mas tudo esta muito estranho. Quero modificar e adicionar algumas informações como:

  • Separar em fieldsets diferentes os campos e botões
  • Colocar uma mensagem informativa abaixo do campo Name
  • Alterar o campo Status de checkbox para radio button.
# app/views/categories/_form.html.erb
 
<% semantic_form_for @category do |form| %>
 
  <% form.inputs do %>
    <%= form.input :name, :hint => "Example: food, books, electronics." %>
    <%= form.input :status, :as => :radio %>
  <% end %>
 
  <% form.inputs do %>
    <%= form.commit_button %>
  <% end %>
 
<% end %>

Podemos ter o controle de tudo! Veja como ficou:

tela04

Vamos para o cadastro de Produtos, gerando o scaffold para o mesmo:

script/generate nifty_scaffold Product category_id:integer name:string description:text price:decimal status:boolean
rake db:migrate

Criando o relacionamento entre Produtos e Categorias:

# app/models/category.rb
class Category < ActiveRecord::Base
 
  has_many :products
 
  validates_presence_of :name
  validates_inclusion_of :status, :in => [true, false]
 
end
 
# app/models/product.rb
class Product < ActiveRecord::Base
 
  belongs_to :category
 
  validates_presence_of :category, :name, :price
  validates_inclusion_of :status, :in => [true, false]
 
end

Nosso formulário está assim:

tela05

Não esta legal, vamos melhorar para:

  • Adicionar um select para escolher uma categoria.
  • Deixar o (*) somente nos campos obrigatórios.
  • Diminuir o tamanho do campo Price.
  • Alterar o campo Status de checkbox para select.
# app/views/products/_form.html.erb
 
<% semantic_form_for @product do |form| %>
 
  <% form.inputs do %>
    <%= form.input :category %>
    <%= form.input :name %>
    <%= form.input :description, :required => false, :input_html => {:rows => 3} %>
    <%= form.input :price, :input_html => {:size => 10} %>
    <%= form.input :status, :as => :select %>
  <% end -%>
 
  <% form.inputs do %>
    <%= form.commit_button %>
  <% end -%>
 
<% end -%>

Olha ai como ele ficou:

tela06

Input Types

Formtastic mapeia diretamente a maioria dos inputs, mas se por algum motivo você precisar alterar o seu tipo (por exemplo, como fizemos com o Status) você pode usar:

  • :select (select para associações)
  • :check_boxes (conjunto de check_box) – uma alternativa ao :select para associações has_many e has_and_belongs_to_many
  • :radio (conjunto de radio) – alternativa ao :select para associações belongs_to
  • :time_zone (select com fusos horários)
  • :password (campo tipo password) – padrão para colunas do tipo :string com ‘password’ no nome do método
  • :text (textarea) – padrão para colunas do tipo :text
  • :date (select para datas) – padrão para colunas do tipo :date
  • :datetime (select para data e hora) – padrão para colunas do tipo :datetime e :timestamp
  • :time (select para hora) – padrão para colunas do tipo :time
  • :boolean (checkbox) – padrão para colunas do tipo :boolean (você também pode usar :select e :radio)
  • :string (campo de texto) – padrão para colunas do tipo :string
  • :numeric (campo de texto, como string) – padrão para colunas do tipo :integer, :float e :decimal
  • :country (menu select com nomes de países) – requer plugin country_select instalado
  • :hidden (campo oculto) – cria um campo oculto

Stylesheets

Mas Jésus, e esse visual feio ai? Tem como melhorar não??

Claro que tem! Tente isso:

script/generate formtastic_stylesheets

Ele vai copiar dois arquivos (formtastic.css e formtastic_changes.css) dentro da pasta public/stylesheets para que você possa personalizar todo o visual do formulário :)

Basta adicionar ambos na view e trabalhar em suas propriedades:

<%= stylesheet_link_tag "formtastic" %>
<%= stylesheet_link_tag "formtastic_changes" %>

Claro que muito mais pode ser feito, como suporte a I18n, upload de imagens, mas isso ficará para um outro post =/

Vale a pena dar uma olhada em sua ótima documentação e nos seus arquivos no Github.

A idéia aqui, foi dar uma introdução e mostrar como ele pode facilitar e ajudar na hora de trabalhar com formulário no Rails.

É isso ai, vou finalizando por aqui :)