ruby on rails - rails - Mejores prácticas de ActionMailer: ¿Método de llamada en el modelo o el controlador?
rails 5 mailer preview (3)
Enviar un correo electrónico generalmente se llama después de una acción en un modelo, pero el correo electrónico en sí es una operación de visualización. Estoy buscando cómo piensas sobre qué pregunta (s) debes hacerte para determinar dónde poner el método de envío de acciones.
Los he visto / usado:
- En un método modelo: ¿mal acoplamiento de preocupaciones relacionadas pero separadas?
- En una devolución de llamada en el modelo (como after_save): la mejor separación, hasta donde yo sé, con mi nivel actual de conocimiento.
- En la acción del controlador, simplemente se siente mal, pero ¿hay situaciones en las que esta sea la forma más inteligente de estructurar el código?
Si quiero saber cómo programar, necesito pensar como un programador, por lo que aprender a pensar a través de soluciones de programación particulares vale la pena meses de codificación por mi cuenta de forma aislada. ¡Gracias!
Bueno, depende.
He usado todas esas opciones y tu punto acerca de "¿por qué debería poner esto?" es bueno.
Si es algo que quiero que ocurra cada vez que se actualiza un modelo de cierta manera, lo pongo en el modelo. Tal vez incluso en una devolución de llamada en el modelo.
A veces solo estás disparando un informe; no hay actualización de nada. En ese caso, normalmente tengo un recurso con una acción de índice que envía el informe.
Si el programa de correo no está realmente relacionado con el modelo que se está modificando, podría ver que lo ponga en una devolución de llamada. No hago eso muy a menudo. Sería más probable que todavía lo encapsulara en el modelo. Lo he hecho, solo que no muy seguido.
Última respuesta, pero quiero racionalizar sobre el tema:
Por lo general, en una aplicación web, desea enviar correos electrónicos como reacción directa a un cliente. O como una tarea de fondo, en caso de que estemos hablando de un tipo de boletín de noticias / correo de notificación.
El modelo es básicamente un mapeador de almacenamiento de datos. Su lógica debe encapsular la gestión / comunicación de datos con el manejo del almacenamiento de datos. Por lo tanto, insertar una lógica que no se relaciona con ella es un poco complicado y, en la mayoría de los casos, incorrecto. Tomemos el ejemplo: el usuario registra una cuenta y debe recibir un correo electrónico de confirmación. En este caso, podría decirse que el correo electrónico de confirmación es un efecto directo de la creación de una nueva cuenta. Ahora, en lugar de hacerlo en la aplicación web, intente crear un usuario en la consola. Suena mal para activar una devolución de llamada en ese caso, ¿verdad? Entonces, la opción de devolución de llamada se rayó. ¿Deberíamos escribir el método en el modelo? Bueno, si se trata de un efecto directo de una acción / entrada del usuario, entonces debe permanecer en ese flujo de trabajo. Lo escribiría en el controlador después de que el usuario se haya creado con éxito. Directamente. Replicar esta lógica en el modelo que se llamará en el controlador de todos modos agrega modularidad innecesaria, y la dependencia de un modelo de registro activo de Action Mailer. Trate de considerar compartir el modelo en muchas aplicaciones, en las que algunas de ellas no quieran usar Action Mailer. Por las razones indicadas, soy de la opinión de que las llamadas de correo deben ser donde tengan sentido, y generalmente el modelo no es ese lugar. Trata de darme ejemplos donde sí lo haga.
Soy consciente de que ha pasado un tiempo, pero las mejores prácticas nunca mueren, ¿verdad? :)
El correo electrónico es, por definición, una comunicación asíncrona (a excepción del correo electrónico de confirmación, pero incluso en este caso, debería ser una buena práctica dejar un retraso antes de tener que confirmarlo).
Por lo tanto, en mi opinión, la forma más lógica de enviarlo es:
- en una acción de fondo (usando Sidekiq o delayyed_job )
- en un método de devolución de llamada: "oye, esta acción se ha llevado a cabo con éxito, tal vez podamos decirle al mundo ahora".
Problema en Rails es que no hay demasiadas devoluciones de llamada (como en JS, por ejemplo): personalmente me parece sucio tener un código como:
after_save :callback
def callback
if test_that_is_true_once_in_the_objects_life
Mailer.send_email()
end
end
Entonces, si realmente quieres pensar como un programador , la idea sería establecer algún sistema de devolución de llamada personalizado en tu aplicación.
P.ej.
def run_with_callback(action, callback_name)
if send(action)
delay.send(callback_name)
end
end
O incluso crear un sistema de eventos en tu aplicación sería una solución decente.
Pero al final esas soluciones son bastante costosas a tiempo para que la gente termine de escribir en línea después de la acción.
def activate
[...]
user.save
Mailer.send_mail
respond_to
[...]
end
que es la forma más cercana a la devolución de llamada en la programación síncrona y los resultados que tienen llamadas de correo en todas partes (en el Model
y en el Controller
).