Rails 2.1.1 - Release de Manutenção

Depois do Release de Manutenção para o Rails 2.0, sai agora o Release de Manutenção para o Rails 2.1. A nova versão, 2.1.1, corrige os problemas de segurança do REXML, além de outras pequenas atualizações.
Para instalar a nova versão: gem install rails -version 2.1.1
Usando o Observer no Rails
Este artigo seria apenas uma dica de como saber o que foi alterado em um objeto, mas para ficar mais fácil e principalmente para quem está dando os primeiros passos em rails resolvi fazer uma pequena introdução sobre o assunto.
O Observer é um objeto que se responsabiliza por "escutar" os eventos que ocorrem com outro objeto. Ou seja, qualquer alteração feito no objeto observado será analizado e poderá executar uma ação. Isto é muito útil para gravar logs, enviar emails e outros.
Vamos criar um projetinho para entender:
1 2 3 4 |
rails observers cd observers script/generate scaffold User name:string phone:string age:integer rake db:migrate |
Acima criamos um projeto e geramos uma entidade User e seus atributos, e migramos o banco. Vamos criar agora a entidade de log e o observer:
1 2 3 4 5 6 7 8 9 10 11 |
script/generate model Log table:string action:string field:string \
old_value:string new_value:string comments:text
exists app/models/
...
script/generate observer user
exists app/models/
exists test/unit/
create app/models/user_observer.rb
create test/unit/user_observer_test.rb
rake db:migrate
|
Feito isto precisamos "ativar" o observer, e para isto basta adicionar no config/enviroment.rb
1 2 3 4 5 6 |
# config/enviroment.rb ... # Activate observers that should always be running # config.active_record.observers = :cacher, :garbage_collector config.active_record.observers = :user_observer |
Agora podemos definir em qual momento ele vai gerar o log, antes ou depois de persistir o objeto:
- before_create, before_destroy, before_update, before_save, before_update
- after_create, after_destroy, after_update, after_save, after_update
Como tudo no rails os nomes já definem o que cada um vai fazer. Vamos gerar um log quando criar ou excluir um usuário. Para isto, vamos abrir o arquivo user_observer.rb
1 2 3 4 5 6 7 8 9 10 |
# app/models/user_observer.rb class UserObserver < ActiveRecord::Observer def after_create(user) Log.create(:table => "user", :action => "create", :comments => "New user added!") end def after_destroy(user) Log.create(:table => "user", :action => "destroy", :comments => "User removed!") end end |
Vamos acessar http://localhost:3000/users e criar um user e veja o log gerado:
1 2 3 4 5 6 |
INSERT INTO "users" ("name", "updated_at", "phone", "age", "created_at")
VALUES('First User', '2008-08-22 12:07:34', '111-1111', 20, '2008-08-22 12:07:34')
INSERT INTO "logs" ("new_value", "updated_at", "comments", "old_value", "action", "field",
"table", "created_at") VALUES(NULL, '2008-08-22 12:07:34', 'New user added!', NULL,
'create', NULL, 'user', '2008-08-22 12:07:34')
|
Simples? Muito. Agora vamos pedir para ele observar o que foi alterado em um objeto:
1 2 3 4 5 6 7 8 9 |
# app/models/user_observer.rb ... def before_update(user) user.changes.each do |key, values| Log.create(:table => "user", :action => "update", :field => key, :old_value => values.first, :new_value => values.last, :comments => "User updated!") end end ... |
O log gerado:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
INSERT INTO "logs" ("new_value", "updated_at", "comments",
"old_value", "action", "field", "table", "created_at") VALUES('2008-08-22 12:29:00',
'2008-08-22 12:29:00', 'User updated!', '2008-08-22 12:07:34', 'update', 'updated_at', 'user',
'2008-08-22 12:29:00')
INSERT INTO "logs" ("new_value", "updated_at", "comments", "old_value", "action", "field",
"table", "created_at") VALUES('222-2222', '2008-08-22 12:29:00', 'User updated!', '111-1111',
'update', 'phone', 'user', '2008-08-22 12:29:00')
INSERT INTO "logs" ("new_value", "updated_at", "comments", "old_value", "action", "field",
"table", "created_at") VALUES(26, '2008-08-22 12:29:00', 'User updated!', 20, 'update',
'age', 'user', '2008-08-22 12:29:00')
UPDATE "users" SET "phone" = '222-2222', "age" = 26, "updated_at" = '2008-08-22 12:29:00'
WHERE "id" = 1
|
Aqui temos apenas uma introdução do que podemos ter com o Observer. Bons estudos.
Gem has_many_select
O problema
Estava fazendo a migração de um sistema para a versão 2.1 do rails, que usa tabelas sem qualquer normalização ou padrão de DB, e me deparei com o seguinte problema:
1 2 3 4 5 6 7 |
class HeaderSale < ActiveRecord::Base
set_table_name("cab_pedido")
set_primary_key("r_e_c_n_o_")
has_many :justifications,
:foreign_key => 'nr_pedido'
end
|
O problema é que tenho uma campo chamado 'r_e_c_n_o_' que é serial(auto incremento), mais não é uma primary key. Pra complicar eu tenho um outro campo, chamado 'cpv_pedido' que a primary key e também é auto incremento (pega o último e soma), ou seja, este banco é um "sonho" para qualquer desenvolvedor.
Quando eu faço um busca:
1 2 3 4 |
x = HeaderSale.find(:first, :conditions => 'cpv_pedido = 193514')
=> 'SELECT * FROM "cab_pedido_vendas" WHERE (cpv_pedido = 193514) LIMIT 1'
x.justifications
=> 'SELECT * FROM "justificativa" WHERE ("justificativa".nr_pedido = 307634)'
|
Mais o correto seria:
=> 'SELECT * FROM "justificativa" WHERE ("justificativa".nr_pedido = 193514)' |
Para resolver este problema, criei a gem has_many_select - não sei porque dei este nome, que temporariamente resolve o problema, já que na próxima versão do rails teremos está opção.
Como usar ?
Primeiro passo é instalar a gem:
1 2 |
gem sources -a http://gems.github.com gem install ozeias-has_many_select |
Depois no environment.rb
require 'has_many_select' |
No relacionamento do model:
1 2 3 4 5 6 7 |
class HeaderSale < ActiveRecord::Base
set_table_name("cab_pedido")
set_primary_key("r_e_c_n_o_")
has_many :justifications,
:foreign_key => 'nr_pedido', :primary_key => 'cpv_pedido'
end
|
O resultado:
1 2 3 4 |
x = HeaderSale.find(:first, :conditions => 'cpv_pedido = 193514')
=> 'SELECT * FROM "cab_pedido_vendas" WHERE (cpv_pedido = 193514) LIMIT 1'
x.justifications
=> 'SELECT * FROM "justificativa" WHERE ("justificativa".nr_pedido = 193514)'
|
E agora?
E agora, se a gem estiver sendo útil para você, não se esqueça de me recomendar no working with rails.
Sugestões, dicas e críticas são bem-vindas.
Update 22/08/2008:
Apesar de ter mudado meu login no github, o nome da gem não foi atualizado. Valeu Marcus. O correto é:
1 2 |
gem sources -a http://gems.github.com gem install ozsantana-has_many_select |
No github: http://github.com/ozeias/has_many_select/tree/master
Rails 2.1 RC1
O DHH acabou de fazer um pequeno anúncio no twitter sobre o lançamento do Rails 2.1 RC1. Segundo ele as gems já estão no servidor beta.
DHH: "Rails 2.1 RC1 has been tagged, the gems are on the beta server, official announcement shortly. But no need holding you back from trying it".
Para acompanhar as novidades acessem o blog do Calos Brando e sua série Edge Rails. Boas novidades estão chegado, vamos testar.
UPDATE:
Para instalar o Rails 2.1 RC1 do servidor beta, basta executar:
sudo gem install rails –source http://gems.rubyonrails.com/ |
Ou:
1 2 3 4 5 6 |
git clone git://github.com/rails/rails.git git pull git checkout v2.1.0_RC1 git checkout master rake rails:update script/dbconsole |
Hoje de manhã saiu um novo episódio do Railscast com o procedimento de atualização.




