Outro recurso que também foi muito solicitado e estará disponível com a versão 2.3 do Rails é uma melhoria nas nested transactions (transações aninhadas).
Atualmente no Rails já podemos aninhar transações, ou em um português mais simples podemos colocar uma transação dentro de outra. Veja um exemplo:
User.transaction do
User.create(:username => 'Kotori')
User.transaction do
User.create(:username => 'Nemu')
raise ActiveRecord::Rollback
end
end
User.find(:all) # => empty
Resumindo o exemplo acima: Criei uma transação e inclui um novo usuário no banco, então criei uma segunda transação dentro da primeira e inclui um segundo usuário, e no fim disparei uma exceção que faz com que a primeira transação e todas as suas filhas sejam desfeitas como você pode ver no resultado do método find.
A novidade é a opção :requires_new. Quando usada em uma sub-transação, caso alguma coisa dê errado somente as alterações feitas dai em diante é que serão desfeitas. Veja um novo exemplo, agora com este recurso habilitado:
User.transaction do
User.create(:username => 'Kotori')
User.transaction(:requires_new => true) do
User.create(:username => 'Nemu')
raise ActiveRecord::Rollback
end
end
User.find(:all) # => Returns only Kotori
Como você pode ver no retorno do método find, ao realizar o rollback somente a inclusão do segundo usuário foi desfeita, já que estou usando a opção :requires_new habilitada na segunda transação.
Nem todo banco de dados tem suporte real a nested transactions. Na verdade, até o momento somente o MS-SQL tem esta funcionalidade. Mas não se preocupe se você estiver usando outro banco de dados, o Active Record consegue emular nested transactions usando savepoints.
ATENÇÃO: Caso você esteja usando o MySQL, então não faça operações DDL em nested transactions que estiverem emulando savepoints. Ou seja, não tente executar algo como ‘CREATE TABLE’ nestes blocos. Isto acontece porque o MySQL automaticamente libera todos os savepoints após executar uma operação DDL. Então quando a transação terminar e tentar liberar os savepoints criados, ocorrerá um erro no banco já que todos os savepoints foram liberados antes da hora. Para entender melhor, veja o exemplo abaixo:
# INICIO
Model.connection.transaction do
# CRIA O SAVEPOINT active_record_1
Model.connection.transaction(:requires_new => true) do
# active_record_1 é automaticamente liberado
Model.connection.create_table(...)
end # LIBERA o savepoint active_record_1
# ^^^^ BOOM! database error!
end
Apesar deste pequeno detalhe, em todos os outros casos este recurso tem funcionado perfeitamente.
Carlos, acompanho seu blog já tem um tempo, e hoje procurando conhecer melhor o controle de transação do Rails me deparei com este post,em outro blog. De uma olhada, acho que você vai achar interessante heheh http://rcaweb.blogspot.com/2009/03/rails-232-novidade-recurso-requiresnew.html
Edson, parece que esta página está fora do ar…
Curioso, acabei de abrir aqui, mas enfim… é praticamente um copy & past do seu post ;)
Olá Carlos Brando,
Realmente pratiquei o copy & past e cometi o erro de não referenciar a fonte.
Minha intenção não foi a de me passar pelo autor da informação, apenas de divulgar sobre as novidades da nova versão do rails expondo um exemplo.
Mas já corrigi este deslize e o exemplo agora aponta diretamente para o seu site. ;)