Posts Tagged ‘form’

Ruby on Rails conversão de datas com I18n

Postado em 09 nov 2009
Categoria(s) Ruby on Rails

Eu estou desenvolvendo uma aplicação que precisa trabalhar com datas com I18n e fazer conversões para salvar a data no banco de dados e exibir para o usuário de acordo com o seu idioma.

Eu estou usando o Date Picker do jQuery em um campo do tipo text_field.

datepicker

Vou mostrar um esboço de como eu fiz isso, em primeiro lugar eu defini no arquivo config/environment.rb o idioma:

config.i18n.default_locale = 'pt-BR'

Depois eu defini no arquivo config/locales/pt-BR.yml os formatos de data:

pt-BR:
  date:
    formats:
      default: "%d/%m/%Y"
      short: "%d de %B"
      long: "%d de %B de %Y"
 
    day_names: [Domingo, Segunda, Terça, Quarta, Quinta, Sexta, Sábado]
    abbr_day_names: [Dom, Seg, Ter, Qua, Qui, Sex, Sáb]
    month_names: [~, Janeiro, Fevereiro, Março, Abril, Maio, Junho, Julho, Agosto, Setembro, Outubro, Novembro, Dezembro]
    abbr_month_names: [~, Jan, Fev, Mar, Abr, Mai, Jun, Jul, Ago, Set, Out, Nov, Dez]
    order: [ :day, :month, :year ]

No meu formulário eu deixei assim:

<% content_for :javascripts do %>
  <%= include_jquery %>
  <%= javascript_include_tag "jquery.maskedinput-1.2.2.min" %>
  <% javascript_tag do %>
    $(document).ready(function() {
      // Adiciona date picker ao campo data de nascimento
      $.datepicker.setDefaults($.extend({showMonthAfterYear: false}, $.datepicker.regional['<%= I18n.locale %>']));
      $("#investor_date_of_birth").datepicker({
        showOn: 'both',
        buttonImage: '/images/calendar.gif',
        buttonImageOnly: false,
        buttonText: '<%= t('ui.admin.crud.datepicker_button_text') %>',
        changeMonth: true,
        changeYear: true,
        yearRange: '1900:<%= Time.now.year %>'
      });
 
      // Adiciona mascara ao campo data de nascimento
      $("#investor_date_of_birth").mask("99/99/9999");
    });
  <% end %>
<% end %>
 
<% form_for [:admin, @investor] do |f| -%>
  <%= f.error_messages %>
 
  <%= f.label :date_of_birth %>
 
  <% if @investor.new_record? %>
    <%= f.text_field :date_of_birth, :class => "smallInput" %>
  <% else %>
    <%= f.text_field :date_of_birth, :value => l(@investor.date_of_birth, :format => :default), :class => "smallInput" %>
  <% end %>
<% end %>

Caso exista o registro é realizado a conversão para exibir a data corretamente no formulário, não é necessário fazer conversão para salvar no banco de dados, o Rails já faz isso automaticamente.

Se você gostou desse texto e acha que ajudou você, me recomende: Recommend Me.

  • Share/Bookmark

Ruby on Rails plugin tableless_model

Postado em 11 ago 2009
Categoria(s) Plugins, Ruby on Rails

tableless_model

Ruby on Rails model sem banco de dados, com todo o poder do ActiveRecord e validações.

A principal utilidade é usar em formulários que não precisam de banco de dados, mas precisam das validações do ActiveRecord, form_for e rotas RESTful. Por exemplo formulário de contato.

Instalação

./script/plugin install git://github.com/patrickespake/tableless_model.git

Geradores

Gerador tableless_model

Cria o esboço de um novo tableless model. Passe o nome do tableless model, em CamelCased ou under_scored, e uma lista de pares de atributos opcionais como argumentos.

Os atributos pares opcionais são column_name:sql_type como argumentos, especificando os atributos do tableless model.

Você não tem que pensar em cada atributos lá na frente, mas ajuda a esboçar um pouco para que você possa começar a trabalhar com o tableless model imediatamente.

Isto gera uma classe tableless model em app/models, um teste de unidade em test/unit e uma fixture em test/fixtures/singular_name.yml

Exemplos:

./script/generate tableless_model contact

Cria o tableless model Contact, test e fixture:

  • Model: app/models/contact.rb
  • Test: test/unit/contact_test.rb
  • Fixtures: test/fixtures/contacts.yml
./script/generate tableless_model invite name:string body:text email:string

Cria o tableless model Invite com a string name, text body e string email.

Gerador tableless_scaffold

Tableless scaffolds é composto por vários recursos, a partir do model, controller e views, juntamente com um conjunto completo de testes. O recurso está pronto para ser usado como um ponto de partida, sendo RESTful, orientado para o pedido.

Passe o nome do tableless model (na forma singular), em CamelCased ou under_scored, como primeiro argumento, e uma lista de pares de atributos opcionais.

Os pares de atributos opcionais são column_name:sql_type, especificando os atributos do modelo.

Você não tem que pensar em cada atributo lá na frente, mas ajuda esboçar um pouco para que você possa começar a trabalhar com os recursos imediatamente.

Por exemplo ‘tableless_scaffold contact name:string telephone:string firm:string email:string message:text’ dá-lhe um tableless model com cinco atributos, um controlador para lidar com a criação, formulário para criar os contatos e routas declaradas em config/routes.rb.

Se você quiser remover todos os arquivos gerados, execute:

script/destroy scaffold ModelName

Exemplos:

./script/generate tableless_scaffold invite
./script/generate tableless_scaffold contact name:string telephone:string firm:string email:string message:text

Tipos de colunas disponíveis nos tableless_models

1
2
3
4
5
6
7
class ModelName < TablelessModel
  column :column_name1, :column_type
  column :column_name2, :column_type
  column :column_name3, :column_type
  column :column_nameN, :column_type
  ...
end

Tipos de colunas (column_type) disponíveis:

  • :string
  • :text
  • :integer
  • :float
  • :decimal
  • :datetime
  • :timestamp
  • :time
  • :date
  • :binary
  • :boolean

Validações do ActiveRecord funcionam perfeitamente

1
2
3
4
5
6
7
8
9
10
11
class Contact < TablelessModel
  column :name, :string
  column :telephone, :string
  column :firm, :string
  column :email, :string
  column :message, :text
 
  validates_presence_of :name, :email, :message
  validates_format_of :email, :with => /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i
  validates_length_of :message, :minimum => 3
end

Exemplo completo usando tableless_scaffold gerador

Criar o tableless scaffold

./script/generate tableless_scaffold contact name:string telephone:string firm:string email:string message:text

Adicionar as validações no model

Abra o arquivo app/models/contact.rb e adicione as validações:

1
2
3
4
5
6
7
8
9
10
11
12
class Contact < TablelessModel
  column :name, :string
  column :telephone, :string
  column :firm, :string
  column :email, :string
  column :message, :text
 
  # Validations
  validates_presence_of :name, :email, :message
  validates_format_of :email, :with => /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i
  validates_length_of :message, :minimum => 3
end

Execute

./script/server

Abra o seu navegador em: http://localhost:3000/contacts/new

Exemplo completo usando tableless_model gerador

Criar tableless model

./script/generate tableless_model contact name:string telephone:string firm:string email:string message:text

Adicionar as validações no model

Abra o arquivo app/models/contact.rb e adicione as validações:

1
2
3
4
5
6
7
8
9
10
11
12
class Contact < TablelessModel
  column :name, :string
  column :telephone, :string
  column :firm, :string
  column :email, :string
  column :message, :text
 
  # Validations
  validates_presence_of :name, :email, :message
  validates_format_of :email, :with => /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i
  validates_length_of :message, :minimum => 3
end

Criar o controlador

./script/generate controller contacts new create

Adicionar os códigos das actions:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class ContactController < ApplicationController
  def new
    @contact = Contact.new
  end
 
  def create
    @contact = Contact.new(params[:contact])
 
    if @contact.save # or @contact.valid?
      flash[:notice] = "Contact email sent successfully."
 
      # Send contact email
      #MyMailer.deliver_contact(@contact)
 
      redirect_to new_contact_path
    else
      render :action => "new"
    end
  end
end

Criar as routas para os contacts

Abra o arquivo config/routes.rb e adicione a linha:

1
2
3
4
ActionController::Routing::Routes.draw do |map|
  map.resources :contacts, :only => [:new, :create]
  ...
end

Criar o formulário de contato

Abra o arquivo app/views/contacts/new.html.erb e adicione o conteúdo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<% form_for(@contact) do |f| %>
  <%= f.error_messages %>
 
  <%= f.label :name %>
  <%= f.text_field :name %>
 
  <%= f.label :telephone %>
  <%= f.text_field :telephone %>
 
  <%= f.label :firm %>
  <%= f.text_field :firm %>
 
  <%= f.label :email %>
  <%= f.text_field :email %>
 
  <%= f.label :message %>
  <%= f.text_area :message %>
 
  <%= f.submit "Send" %>
<% end %>

Apague o arquivo app/views/contacts/create.html.erb.

Execute

./script/server

Abra o seu navegador em: http://localhost:3000/contacts/new

Documentação

http://lab.patrickespake.com/tableless_model

Código fonte

http://github.com/patrickespake/tableless_model

Se você gostou desse texto e acha que ajudou você, me recomende: Recommend Me.

  • Share/Bookmark

Ruby on Rails como colocar um captcha no formulário, instalação e uso do plugin Simple Captcha

Postado em 01 fev 2009
Categoria(s) Ruby on Rails

Conheço um plugin chamado Simple Captcha, eu acho ele muito bom e satifaz todas as minhas necessidades.

Vou explicar como instalar e usar:

Instalação ImageMagick e RMagick::

Como o captcha trabalha com geração dinâmica de imagens e necessário instalar essas libs:

1
2
3
sudo apt-get install imagemagick
sudo apt-get install libmagick9-dev
sudo gem install rmagick

Instalação do plugin Simple Captcha:

No diretório do projeto digite o seguinte:

1
ruby script/plugin install svn://rubyforge.org/var/svn/expressica/plugins/simple_captcha

Configuração da aplicação:

No diretório do projeto digite:

1
rake simple_captcha:setup

O comando acima irá criar um arquivo de migração para armazenar os captchas gerados no banco de dados, também irá criar um partial para exibir o captcha na view.

Agora faça o migrate:

1
rake db:migrate

É necessário adicionar uma rota no arquivo config/routes.rb, essa rota será responsável por gerar as imagens:

1
map.simple_captcha '/simple_captcha/:action', :controller => 'simple_captcha'

Adicione a seguinte linha no arquivo app/controllers/application.rb:

1
2
3
ApplicationController < ActionController::Base
  include SimpleCaptcha::ControllerHelpers
end

Como usar:

No seu formulário na view adicione o seguinte:

1
<%= show_simple_captcha( : object=> "user" ) %>

Onde : object => “user” é o nome do seu model.
Obs.: Eu deixei separado o dois pontos, : object => “user” porque o wordpress troca por desenhos smiley, na hora de codificar deixa tudo junto.

No model adicione a seguinte linha:

1
2
3
class User < ActiveRecord::Base
  apply_simple_captcha
end

Agora no controller ao invés de usar:

1
@user.save

Use:

1
@user.save_with_captcha

O método @user.save funciona corretamente, mas não leva em consideração o novo campo captcha, por isso é necessário usar o método @user.save_with_captcha.

Outras opções de uso e configuração, para ver outras alternativas eu sugiro que leia: http://expressica.com/simple_captcha/.

Se você gostou desse texto e acha que ajudou você, me recomende: Recommend Me.

  • Share/Bookmark

Ext JS carregar um combo box a partir de outro combo box

Postado em 16 jan 2009
Categoria(s) Ext JS, JavaScript

Nesse exemplo será construído dois combo boxs com framework Ext JS, um de estados e outro de cidades.

O combo box de cidades será carregado após selecionar o estado, ou seja, será exibido as cidades de um determinado estado.

Crie duas variáveis globais:

1
2
var SELECTED_STATE;
var CITY_STORE;

Crie o data store de estados e o combo box de estados:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var state_store = new Ext.data.JsonStore({
  fields: [
    {name: 'id', type: 'int'},
    {name: 'short', type: 'string'}
  ],
  proxy: new Ext.data.HttpProxy({
    url: 'getStates.php',
    method: 'GET'
  })
});
 
var state = new Ext.form.ComboBox({
  store: state_store,
  displayField: 'short',
  fieldLabel: 'Estado',
  name: 'state',
  anchor: '100%',
  emptyText: 'Selecione o estado...',
  typeAhead: true,
  forceSelection: true,
  triggerAction: 'all',
  selectOnFocus: true
});

Quando o combo box de estado for iniciado, será disparado uma requisição ajax para getStates.php e deve retorna um json de estados com os atributos id e short (usado para o nome curto do estado, por exemplo PR, SP, RJ, …)

Agora vamos criar o combo box de cidades:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
CITY_STORE = new Ext.data.JsonStore({
  fields: [
    {name: 'id', type: 'int'},
    {name: 'name', type: 'string'}
  ],
  proxy: new Ext.data.HttpProxy({
    url: 'getCities.php',
    method: 'GET'
  })
});
 
var city = new Ext.form.ComboBox({
  store: CITY_STORE,
  displayField: 'name',
  fieldLabel: 'Cidade',
  name: 'city',
  anchor: '100%',
  emptyText: 'Selecione a cidade...',
  typeAhead: true,
  forceSelection: true,
  triggerAction: 'all',
  selectOnFocus: true
});

Repare que o data store de cidades usa a variável global CITY_STORE, vamos precisar acessar esse data store dentro de algumas funções.

A ideia aqui é quando for selecionado o estado, armazenar o id selecionado e usar para fazer a requisição ajax para getCities.php, buscando somente pelas cidades de um determinado estado. Para fazer isso precisamos adicionar um listener na combo box de estados:

1
state.addListener('select', onStateSelect);

Agora crie a função onStateSelect:

1
2
3
4
5
function onStateSelect(obj, record, index) {
  SELECTED_STATE = record.get('id');
  CITY_STORE.removeAll();
  CITY_STORE.load();
}

No código acima usamos a variável global SELECTED_STATE para armazenar o id do estado selecionado, também limpamos o data store de cidades caso já tenha sido uma requisição é zerado o combo box de cidades e disparamos a requisição para preencher o combo box de cidades.

Mas só fazendo isso não vai funcionar, é necessário adicionar o parâmetro state_id na requisição ajax para obter as cidades, podemos fazer isso da seguinte forma, adicione o código:

1
2
3
4
CITY_STORE.proxy.on('beforeload', function(proxy, params) {
  city.clearValue();
  params.state_id = SELECTED_STATE;
});

Antes de fazer a requisição ajax para as cidades, será adicionado o parâmetro state_id, usando um controle de eventos no Ext JS. Também limpo aqui o valor selecionado na combo box de cidades.

Bom, o Ext JS é fodinha mesmo, é meio complicado, a documentação é tão ampla que quebra as pernas. Ae você tem que balancear para ver até que ponto vale a pena usar ele. Uma coisa é verdade ele gera ótimas interfaces, mas toda essa sintaxe parece muito com o Swing do Java (coisa que eu não gosto em nada :-().

Esse exemplo é meio genérico, dá para usar tanto em combo box isolados ou com formulários em ext. Por isso você tem que fazer alguns ajustes para imprimir os combo boxs.

  • Share/Bookmark

Instalando e usando o plugin paperClip no Ruby on Rails

Postado em 18 dez 2008
Categoria(s) Ruby on Rails

O plugin paperClip do Ruby on Rails é muito bacana, agiliza muito a vida, com ele é possível fazer upload de imagens e já gerar várias dimensões da imagem.

Vou explicar como instalar e como usar.

Instalação:

Faça o download do paperClip: http://github.com/tarballs/thoughtbot-paperclip-18c0246c11c51dafa77b6367ddaf730684d0e752.zip

Descompacte o arquivo e renomei o diretório extraído para paperclip.

Coloque esse diretório dentro de seu_projeto/vendor/plugins/paperclip.

Você vai precisar do imageMagick, através dele o paperClip faz o resize nas imagens. Para instalar no Ubuntu 8.04 faça:

1
sudo apt-get install imagemagick

Configuração:

Para o paperClip funcionar você vai precisar que exista 4 novas colunas na sua tabela são elas: image_file_name, image_content_type, image_file_size, image_updated_at.

Esse nome image_… pode ser qualquer outra coisa por exemplo: avatar_…, foto_…

Seguindo essa ideia você poderia ter um migrate mais ou menos assim:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class CreateTournaments < ActiveRecord::Migration
  def self.up
    create_table :tournaments do |t|
      t.column :name,               :string,    :limit => 100, :null => false
      t.column :description,        :text,      :null => true
      t.column :image_file_name,    :string
      t.column :image_content_type, :string
      t.column :image_file_size,    :integer
      t.column :image_updated_at,   :timestamp
      t.column :is_active,          :boolean,   :null => false, :default => false
      t.column :start_date,         :date,      :null => false
      t.column :end_date,           :date,      :null => false
      t.column :created_at,         :timestamp, :null => false
      t.column :updated_at,         :timestamp, :null => false
    end
  end
 
  def self.down
    drop_table :tournaments
  end
end

Agora é necessário informar o seu model que existirá anexos e que formatos são aceitos:

1
2
3
4
5
6
7
8
9
10
class Tournament < ActiveRecord::Base
  has_attached_file :image,
                    :styles => {:large => '600x600>', :medium => '300x300>', :small => '150x150>', :thumb => '50x50>'},
                    :path => ":rails_root/public/images/:class/:id/:style_:basename.:extension",
                    :url => "/images/:class/:id/:style_:basename.:extension"
 
  validates_uniqueness_of :name
  validates_presence_of   :name, :start_date, :end_date
  validates_attachment_content_type :image, :content_type => ['image/jpeg', 'image/png', 'image/gif']
end

O interessante da linha abaixo, é que posso definir todos os tamanhos de imagens que desejo gerar em cima da imagem original, nesse trecho de código eu também alterei o path de armazenamento das imagens, fiz as imagens ficarem no diretório public_html/images/tournaments/id_do_banco_de_dados/imagens_em_diversas_dimensões:

1
2
3
4
  has_attached_file :image,
                    :styles => {:large => '600x600>', :medium => '300x300>', :small => '150x150>', :thumb => '50x50>'},
                    :path => ":rails_root/public/images/:class/:id/:style_:basename.:extension",
                    :url => "/images/:class/:id/:style_:basename.:extension"

A linha seguinte informa os tipos de mime types aceitos:

1
  validates_attachment_content_type :image, :content_type => ['image/jpeg', 'image/png', 'image/gif']

Agora você precisa definir que o seu formulário de cadastro trabalha com multipart, para enviar dados binários:

1
2
3
4
  <% form_for :tournament, @tournament, :url => { :action => 'create' }, :html => { :multipart => true } do |form| %>
    <%= render :partial => 'form', :locals => { :form => form } %>
    <div class="submit"><%= submit_tag "Criar" %></div>
  <% end %>

No código acima eu chamo o partial _form.rhtml, segue o seu conteúdo abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<%= error_messages_for 'tournament' %>
 
<!--[form:tournament]-->
<p><label for="tournament_name">Nome</label>
<%= form.text_field :name  %></p>
 
<p><label for="tournament_description">Descrição</label>
<%= form.text_area :description  %></p>
 
<p><label for="tournament_image">Imagem</label>
<%= form.file_field :image %></p>
 
<p><label for="tournament_is_active">Ativo</label>
<%= form.check_box :is_active  %>
 
<p><label for="tournament_start_date">Data de início</label>
<%= form.date_select(:start_date, :order => [:day, :month, :year], :use_month_numbers => true) %></p>
 
<p><label for="tournament_end_date">Data de término</label>
<%= form.date_select(:end_date, :order => [:day, :month, :year], :use_month_numbers => true)  %></p>
<!--[eoform:tournament]-->

Nesse partial _form.rhtml é declarado o campo para upload da imagem:

1
<%= form.file_field :image %>

Perceba que na tabela do banco de dados não existe a coluna chamada image, mas sim aquelas 4 que criei no migrate. Aqui que entra a mágica do paperClip juntamente com o model, ele consegue fazer o upload da imagem e definir os valores para os 4 campos no model.

Para exibir as imagens e suas diversas proporções use:

1
2
3
4
<%= image_tag @tournament.image.url(:thumb)  %>
<%= image_tag @tournament.image.url(:small)  %>
<%= image_tag @tournament.image.url(:medium)  %>
<%= image_tag @tournament.image.url(:large)  %>

Pronto! Depois de pegar o jeito com o paperClip você vai dar risada a toa. ;-)

Se você gostou desse texto e acha que ajudou você, me recomende: Recommend Me.

  • Share/Bookmark