2010-02-11 9 views
11

Tengo dos modelos: usuario y empresa. Ambos se crean de una forma y estoy usando una transacción como esta:La transacción de rieles no se revierte en el error de validación

User.transaction do 

    @user.save! 

    @company.user = @user 
    @company.save! 

    @user.reload 
    @user.company = @company 
    @user.save! 

flash[:notice] = "Thank you for your registration." 
    redirect_to_index 
end 

El usuario se guarda en la base de datos incluso cuando una de las validaciones de la compañía falla. Intenté agregar el manejo de errores explícito de ActiveRecord :: RecordInvalid pero no ayudó. Pensé que la validación provocaría el error de deshacer la transacción de todos modos. Cualquier ayuda es muy apreciada.

Gracias

+10

¿Qué RDBMS estás usando? ¿Admite transacciones (MyISAM vs InnoDB)? –

+0

Ah, creo que eso es todo. La mayoría de las tablas son innoDB, pero hay algunas myisam. Gracias – Shagymoe

+0

Vea también http://stackoverflow.com/questions/2481806/how-do-i-get-save-no-exclamation-point-semantics-in-an-activerecord-transaction –

Respuesta

-2

http://tempe.st/2007/05/transaction-in-rails/

creo que se debe utilizar un bloque final comenzará fuera del bucle de transacción.

+0

No es cierto. Si quieres hacer algo más que una simple reversión, necesitarás un bloque 'begin'..'rescue'..''nd', pero un manejador de excepciones en la parte superior de la pila puede manejarlo tan fácilmente después de que la reversión sea hecho. También puede dejar que Rails lo maneje y muestre una página de error. –

0

Usted tendrá que considerar estos escenarios

  1. Utilice un sistema de base de datos que soporta la transacción
  2. Re-Factor que codifican para un enfoque más lógico

A modo de ejemplo, si sólo tiene una relación uno-a-uno, se puede manejar de manera más optimizada

Company has_one User 
User belongs_to Company 

Ahora, en el modelo de empresa

@company.user.build(user_attributes) 
@company.save # will save company as well as user 

No lo he probado como ejemplo. Fuera de mi mente. ¿He entendido el problema correctamente?

2

Debe utilizar un motor de base de datos que admita transacciones ACID. Para mysql eso es INNODB.

show table status\G 

Si los usuarios o empresas es no utilizando el motor InnoDB, se puede cambiar w/este comando.

ALTER TABLE <table name> ENGINE INNODB; 

la excepción lanzada desde @company.save! * deben dar lugar a un comando ROLLBACK para ser enviados a la base de datos. puede verificar esto en la consola/archivo de registro cuando ejecuta script/servidor con el nivel de registro DEBUG.

+0

No detectar una excepción ActiveRecord :: RecordInvalid dentro de una transacción porque esta excepción invalida la transacción en algunas bases de datos como Postgres. Una vez que la transacción ha sido invalidada, debe reiniciarla desde el principio para que funcione correctamente. http://markdaggett.com/blog/2011/12/01/transactions-in-rails/ – macsig

0

guardar() y destroy() están siempre en transacción (ver http://railsapi.com/doc/rails-v2.3.5/classes/ActiveRecord/Transactions/ClassMethods.html).

Lo que creo que quieres hacer es

begin 
    @company = Company.create!(params[:company]) 
    @user = User.create!(params[:user]) { |user| user.company => @company } 
    rescue => ex 
    # ... handle your validation errors 
    end 

Esto resolvería el problema de que cuando fallan las validaciones de la empresa una excepción será levantado y la declaración User.create nunca se ejecuta.

1

intentando guardar una nueva entrada y revisar una entrada existente (basada en la nueva entrada) al mismo tiempo, se encontró con un problema similar. Intentó la transacción con la validación de rescate fallido, pero optó por esto en su lugar:

if @new_entry.valid? && @existing_entry.valid? 
    ActiveRecord::Base.transaction do 
    @new_entry.save! 
    @existing_entry.save! 
    end 
end 

el código valida primero. no intenta guardar a menos que ambas entradas sean válidas.la semántica de la transacción protege contra la entrada incompleta en otros errores si la base de datos lo admite. espero que sea una buena solución.

Cuestiones relacionadas