Rails 3: retroceder para after_create

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?

preguntado el 27 de julio de 12 a las 18:07

¿Puede un usuario inscribirse varias veces? Si no, simplemente agregaría los campos adicionales directamente en la tabla de usuarios. -

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. -

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. -

Si el usuario se vuelve a dar de alta validará por email or driver 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í el enrollments 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. -

4 Respuestas

Volviendo false de 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 de github.com/rails/rails/issues/33192 - marca kenny

En Rails 5, necesitas usar throw :abort para revertir la cadena ActiveRecord.

enter image description here

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

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

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 or haz tu propia pregunta.