Rails 3: retroceder para after_create
Frecuentes
Visto 8,675 equipos
7
Tengo un formulario de inscripción.
Cuando el usuario se inscribe, se supone que la aplicación guarda los datos en el enrollments
mesa y en la users
mesa. (Necesito esta separación porque el perfil del usuario puede cambiar pero hay que archivar los datos que ingresó para esa inscripción en particular. Así que aunque luego el usuario cambie su apellido, en el formulario de inscripción tendré su información inicial).
Así que estaba pensando en guardar datos en el enrollments
table luego haga una llamada after_create, como esta...
class Enrollment < ActiveRecord::Base
after_create :save_corresponding_user
def save_corresponding_user
user = User.new
user.full_name = self.user_full_name
user.email = self.user_email
user.mobile_phone = self.user_mobile_phone
user.save
end
end
El problema es, ¿qué pasa si no se puede guardar al usuario por algún motivo? ¿Cómo puedo revertir y destruir los datos recién guardados del enrollments
¿mesa?
4 Respuestas
12
Volviendo false
del after_create
no hará nada.
Toda la cadena de devolución de llamada está envuelta en una transacción. Si algún método de devolución de llamada anterior devuelve exactamente falso o genera una excepción, la cadena de ejecución se detiene y se emite un ROLLBACK; después de que las devoluciones de llamada solo puedan lograrlo generando una excepción.
Además, debes raise ActiveRecord::Rollback
:
Rails volverá a generar cualquier excepción que no sea ActiveRecord::Rollback después de que se detenga la cadena de devolución de llamada. Generar una excepción que no sea ActiveRecord::Rollback puede romper el código que no espera métodos como save y update_attributes (que normalmente intentan devolver verdadero o falso) para generar una excepción.
http://guides.rubyonrails.org/active_record_callbacks.html#halting-execution
Hago algo como esto:
after_create do
if condition
errors.add(:attr, 'Blah blah blah.')
raise ActiveRecord::Rollback
end
end
Para rieles 3: http://guides.rubyonrails.org/v3.2.13/active_record_validations_callbacks.html#halting-execution
respondido 03 nov., 15:20
Encontré raise ActiveRecord::Rollback
no funciona pero esto lo hizo: raise ActiveRecord::RecordInvalid, self
del github.com/rails/rails/issues/33192 - marca kenny
1
En Rails 5, necesitas usar throw :abort
para revertir la cadena ActiveRecord.
Puede ver la lista de manejo de operaciones en diferentes versiones de Rails junto con las devoluciones de llamada antes y después. Para una mejor aclaración, consulte el concepto de detener las ejecuciones. Por favor, siga el enlace dado a continuación.
https://guides.rubyonrails.org/active_record_callbacks.html#halting-execution
Respondido 29 Jul 19, 11:07
11
after_create es una parte de la transacción que guarda el modelo actual. Por lo tanto, si su código falla o si after_create devuelve falso, debería revertir la transacción actual e invalidar el enrollment
ahorro.
Si desea simular esto, agregue esto a su after_create y vea si todo funciona como se esperaba:
raise Exception.new("CRASH")
Respondido 27 Jul 12, 18:07
la reversión no ocurre si está utilizando una base de datos no transaccional como mongodb - florín PT
Si after_create devuelve falso, tampoco parece revertir la transacción (solo la excepción). Al menos en Rails 4. - Djburdick
@djburdick Una transacción por defecto solo debe revertirse si se genera una excepción. Así que este es el comportamiento esperado. Creo que esta respuesta es ligeramente incorrecta con respecto a ese detalle. - leishman
1
Como mencionó @anthonyalberto, after_create ya es parte de la transacción. Para definir una transacción, usaría algo como esto en su controlador:
Enrollment.transaction do
@enrollment.save!
end
Eso es realmente todo lo que necesita hacer, si falla el guardado de la inscripción o el guardado del usuario, se revertirá toda su transacción. Aquí hay más información: http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html
Respondido 27 Jul 12, 19:07
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas ruby-on-rails ruby or haz tu propia pregunta.
¿Puede un usuario inscribirse varias veces? Si no, simplemente agregaría los campos adicionales directamente en la tabla de usuarios. - Anthony Alberto
Bueno, en realidad, es un padre/tutor que inscribe a un niño en una guardería. Entonces sí, el padre puede inscribir a un niño varias veces. - leonel
Para mí, parece que poner save_corresponding_user en after_create va a ser un problema. ¿Qué sucede cuando el usuario se inscribe de nuevo? No le gustaría crear un nuevo objeto de usuario para ellos. Además, ¿la tabla de inscripciones probablemente no tenga una columna de ID de usuario? Eso no se completaría en su código anterior. Si fuera yo, simplemente envolvería la creación de la inscripción y el usuario en una transacción, que manejará la reversión de ambos en caso de error. - Jeff Steil
Si el usuario se vuelve a dar de alta validará por
email
ordriver license/id #
. Se supone que los administradores deben saber o preguntar si una persona ya inscribió a sus hijos, por lo que en lugar de ir a la Inscripción por primera vez, van al perfil de los padres y van a un formulario diferente. sí elenrollments
Se supone que la tabla tiene una columna de ID de usuario, no incluí muchas columnas en el ejemplo por simplicidad. Examinaré las transacciones, ¿hay algún buen tutorial que recomendaría? No veo nada relacionado en los Railscasts. - leonel