segunda-feira, 6 de outubro de 2008

Populando select com Ajax on Rails

Esquema simples para popular um select com ajax.

1º - Criar o projeto "MeusAmigos"
> rails MeusAmigos
> cd MeusAmigos

2º - Criar "Estado", "Cidade" e "Amigo"
> ruby script/generate Model Estado nome:string
> ruby script/generate scaffold Cidade estado:references nome:string
> ruby script/generate scaffold Amigo cidade:references nome:string endereco:string

3º - na migrate xxxxxxx_create_cidades.rb
...

def self.up
create_table :cidades do |t|
t.references :estado
t.string :nome
end
execute( insert_estados )
execute( insert_cidades )
end

def self.insert_estados
<<-END_OF_DATA
insert into estados values
( 1, 'Acre' ),
( 2, 'Alagoas' ),
( 3, 'Amapá' ),
( 4, 'Amazonas' ),
( 5, 'Bahia' ),
( 6, 'Ceará' ),
( 7, 'Distrito Federal' ),
( 8, 'Espírito Santo' ),
( 9, 'Goiás' ),
( 10, 'Maranhão' ),
( 11, 'Mato Grosso' ),
( 12, 'Mato Grosso do Sul' ),
( 13, 'Minas Gerais' ),
( 14, 'Pará' ),
( 15, 'Paraíba' ),
( 16, 'Paraná' ),
( 17, 'Pernambuco' ),
( 18, 'Piauí' ),
( 19, 'Rio de Janeiro' ),
( 20, 'Rio Grande do Norte' ),
( 21, 'Rio Grande do Sul' ),
( 22, 'Rondônia' ),
( 23, 'Roraima' ),
( 24, 'Santa Catarina' ),
( 25, 'São Paulo' ),
( 26, 'Sergipe' ),
( 27, 'Tocantins' )
END_OF_DATA
end

def self.insert_cidades
<<-END_OF_DATA
insert into cidades values
( 1, 1, 'Rio Branco' ),
( 2, 2, 'Maceió' ),
( 3, 3, 'Macapá' ),
( 4, 4, 'Manaus' ),
( 5, 5, 'Salvador' ),
( 6, 6, 'Fortaleza' ),
( 7, 7, 'Brasília' ),
( 8, 8, 'Vitória' ),
( 9, 9, 'Goiânia' ),
( 10, 10, 'São Luís' ),
( 11, 11, 'Cuiabá' ),
( 12, 12, 'Campo Grande' ),
( 13, 13, 'Belo Horizonte' ),
( 14, 14, 'Belém' ),
( 15, 15, 'João Pessoa' ),
( 16, 16, 'Curitiba' ),
( 17, 17, 'Recife' ),
( 18, 18, 'Teresina' ),
( 19, 19, 'Rio de Janeiro' ),
( 20, 20, 'Natal' ),
( 21, 21, 'Porto Alegre' ),
( 22, 22, 'Porto Velho' ),
( 23, 23, 'Boa Vista' ),
( 24, 24, 'Florianópolis' ),
( 25, 25, 'São Paulo' ),
( 26, 26, 'Aracaju' ),
( 27, 27, 'Palmas' )
END_OF_DATA
end
...

4º - criando o relacionamento

class Estado < ActiveRecord::Base
has_many :cidades
end

class Cidade < ActiveRecord::Base
belongs_to :estado
has_many :amigos
end

class Amigo < ActiveRecord::Base
belongs_to :cidade
end

5º - no controller Application

class ApplicationController < ApplicationController
...
protected
def carrega_estados
estados ||= Estado.find(:all).collect { |e| [e.nome, e.id] }
end
end

6º - nos controllers Cidades e Amigos

class ...Controller < ApplicationController

before_filter :carrega_estados
...

7º - nas views new e edit de cidades

...
<%= f.label :estado %><br />
<%#= f.text_field :estado %>
<%= f.select :estado_id, @estados, :prompt => '-- selecione --' %>
...

8º - nas views new e edit de amigos
...
<% form_for(@amigo) do |f| %>
<%= render :partial => 'form',
:locals => {:f => f, :btn_label => 'msg Criar ou Alterar'} %>
<% end %>
...

9º - crie um partial amigos/_form.html.erb om o seguinte código:

...
<%= f.error_messages %>
<table>
<td>
<%= f.label :estado %><br />
<%= select( '', 'seleciona_estado', @estados) %>
</td>
<td>
<div id='cidades_container'>
Primeiro selecione o estado
</div>
</td>
</tr>
</table>

<%= observe_field('_seleciona_estado', :frequency => 0.25,
:update => 'cidades_container',
:url => { :action => :adiciona_cidades },
:with => "'estado_id='+value") %>

<p>
<%= f.label :nome %><br />
<%= f.text_field :nome %>
</p>

<p>
<%= f.label :endereco %><br />
<%= f.text_field :endereco %>

</p>
<p> <%= f.submit btn_label %> </p>

10º - crie uma view amigos/adiciona_cidades.html.erb com o seguinte código:
Cidades do <i><%= @estado.nome %></i><br/>
<%= select( :amigo, :cidade_id, @cidades ) %>

11º - no controller Amigos inclua:
def adiciona_cidades
@cidades = Cidade.find_all_by_estado_id( params[:estado_id] ).collect { |c| [c.nome, c.id] }
@estado = Estado.find( params[:estado_id] )
end

12º - crie a view layouts/application.html.erb com o seguinte código:
<html>
<head>
<title><%= controller.action_name %></title>
<%= javascript_include_tag :defaults %>
<%= stylesheet_link_tag 'scaffold' %>
</head>
<body>
<%= link_to 'Cidades', cidades_path %>
<%= link_to 'Amigos', amigos_path %>
<p style="color: green"><%= flash[:notice] %></p>
<%= yield %>
</body>
</html>

rode a migration
>> rake db:migrate

rode o servidor
>> ruby script/server

http://localhost:3000/amigos