2010-02-18 11 views

Respuesta

24
a.each(&:save) 

Para ello, será B#save en cada elemento de la matriz.

+9

Y envuelva eso en una B.transaction para que todo se guarde en una operación atómica. – Farrel

+2

Nunca llame 'save', revise el valor de retorno (true oder false) o use' .save! 'Para permitir que los rails hagan una excepción cuando algo no está bien. – reto

39
B.transaction do 
    a.each(&:save!) 
end 

Esto creará una transacción que recorre cada elemento de la matriz y llama a element.save en ella.

Puede leer sobre ActiveRecord Transactions y the each method en las API de Rails y Ruby.

+1

¡Atención! Esto no funcionará a menos que uses 'save!'. Parece que la transacción solo se cancela si hay una excepción. – Alexey

+0

Yikes. Tienes razón. He actualizado la respuesta. –

+0

Ahora necesita atrapar 'ActiveRecord :: RecordInvalid' en alguna parte. – Alexey

0

Envolver save en la transacción no será suficiente: si una validación no se pasa, no será una excepción levantada y sin reversión disparado.

puedo sugerir esto:

B.transaction do 
    a.each do |o| 
    raise ActiveRecord::Rollback unless o.save 
    end 
end 

Sólo haciendo B.transaction do a.each(&:save!) end no es una opción ya sea, porque el bloque de transacción no rescatará ninguna excepción que no sea ActiveRecord::Rollback, y la aplicación se estrellaría en la validación fallida.

No sé cómo verificar después si los registros se han guardado.


actualización. Como alguien ha downrated mi respuesta, supongo que la persona que estaba buscando una solución de cortar y pegar :), asi que aquí hay alguna manera (feo :)) para procesar Falla/valor éxito:

save_failed = nil 
B.transaction do 
    a.each do |o| 
    unless o.save 
     save_failed = true 
     raise ActiveRecord::Rollback 
    end 
    end 
end 
if save_failed 
    # ... 
else 
    # ... 
end 
+0

'¡guardar!'es perfecto, el bloque' transaction do' revertirá automáticamente todos los demás cambios. – reto

+0

Debería detectar excepciones manualmente fuera de la transacción si falla una validación. – Alexey

+0

Todo lo que digo es: tienes dos opciones a) manejar la validación inmediatamente después del 'save' usando el valor de retorno b) dejar que el proceso/trabajo se cuelgue usando' save! ', Hay (en casi todos los casos) no hay término medio. Un 'save' solitario (sin manejar su valor de retorno) es una gran señal de advertencia. La transacción simplemente asegura que todo lo demás se restaure también. – reto

8

Así Creo que necesitamos un término medio para las excepciones de Alexey y abortar la transacción y la solución única de Jordan. ¿Puedo proponer:

B.transaction do 
    success = a.map(&:save) 
    unless success.all? 
    errored = a.select{|b| !b.errors.blank?} 
    # do something with the errored values 
    raise ActiveRecord::Rollback 
    end 
end 

Esto le dará un poco de ambos mundos: una transacción con rollback, el conocimiento de que registra e incluso no le da acceso a los errores de validación en el mismo.

+1

En lugar de '! B.errors.blank?', ¿Por qué no 'b.errors.present?' – moveson

+0

también podría ser 'a.reject {| b | b.errors.blank?} '. Principalmente porque fue hace casi 3 años y fue una respuesta fuera de lo común. También porque Ruby, ¿estoy en lo cierto? – kayakyakr

2

Sé que esto es una vieja pregunta, pero estoy sorprendido nadie pensó en esto:

B.transaction do 
    broken = a.reject { |o| o.save } 
    raise ActiveRecord::Rollback if broken.present? 
end 

if broken.present? 
    # error message 
end 
+0

¡Debería usar guardar! en lugar del aumento. La transacción se encargará del resto. –

+0

@ D.Wonnink sí, pero provocará un cortocircuito en las copias de seguridad adicionales, por lo que solo sabrá sobre la primera que falló, no sobre todas ellas. Esto puede hacer una gran diferencia cuando tienes, por ejemplo, 30 objetos guardados en fila, la mitad de ellos fallaron y tienes que mostrar la validación al usuario de una manera que no lo hará volver a enviar el formulario 15 veces para corregir 15 errores uno después de otro solo para aprender, otra cosa está rota;) – d4rky

Cuestiones relacionadas