Recordatorios de citas con Ruby y Rails
¡Ahoy! Ahora te recomendamos que crees tus recordatorios de citas SMS con la funcionalidad de programación de mensajes integrada de Twilio. Dirígete a la Documentación de recursos de mensajes para obtener más información sobre la programación de mensajes de SMS.
¿Estás listo para implementar recordatorios de citas en tu aplicación móvil? Así es como funciona a un nivel alto:
- Un administrador crea una cita para una fecha y hora futuras y almacena el número de teléfono de un cliente en la base de datos de esa cita
- Un proceso en segundo plano comprueba la base de datos a intervalos regulares y busca citas que requieran el envío de un recordatorio
- A una hora configurada antes de la cita, se envía un recordatorio por SMS al cliente para recordarle su cita
Componentes básicos
Estas son las tecnologías que utilizaremos para conseguir esto:
- Ruby on Rails para crear una aplicación web basada en bases de datos
- El recurso mensajes de la API REST de Twilio para enviar mensajes de texto
- Delayed::Job para ayudarnos a programar y ejecutar tareas en segundo plano de forma recurrente
Cómo leer este tutorial
Para implementar los recordatorios de citas, trabajaremos en una serie de historias de usuarios que describen cómo implementar por completo los recordatorios de citas en una aplicación web. Analizaremos el código necesario para satisfacer cada historia y exploraremos lo que necesitábamos añadir en cada paso.
Todo esto se puede hacer con la ayuda de Twilio en menos de media hora.
Creación de una cita
Como usuario, quiero crear una cita con un nombre, números de teléfono de invitado y una hora en el futuro.
Para crear una app de recordatorios de citas automatizada, probablemente deberíamos empezar con una cita. Esta historia requiere que creemos un poco de interfaz de usuario y un objeto de modelo para crear y guardar una Appointment
nueva en nuestro sistema. A un nivel alto, esto es lo que necesitaremos añadir:
- Un formulario para introducir detalles sobre la cita
- Una función de ruta y controlador en el servidor para representar el formulario
- Una función de ruta y controlador en el servidor para manejar la solicitud POST del formulario
- Un objeto de modelo persistente de
Appointment
para almacenar información sobre el usuario
Empecemos por observar el modelo, en el que decidimos qué información queremos almacenar con la cita.
El generador de Rails
Por lo general, en este punto del tutorial, crearíamos nuestro modelo, vista y controlador desde cero (consulta la verificación de cuentas como ejemplo). Pero dado que el modelo de cita es tan sencillo y, solo queremos la estructura CRUD básica, utilizaremos el generador de Rails por primera vez.
Una nota sobre las herramientas
En esta app utilizamos Rails 4, pero será muy similar al 3 y versiones anteriores. También usaremos la biblioteca auxiliar twilio-ruby. Por último, usamos bootstrap para simplificar el diseño, y en este caso hay una gema que generará vistas temáticas de bootstrap llamadas twitter-bootstrap-rails. Revisa estas herramientas cuando tengas una oportunidad, ahora pasemos a generar nuestra estructura.
Generar un modelo, una vista y un controlador
Rails generate es una herramienta de línea de comandos que genera componentes de Rails como modelos, vistas, pruebas y mucho más. Para nuestros propósitos vamos a utilizar el gran e importante generador, scaffold
para generar todo a la vez.
Así es como lo hicimos. Desde nuestra app Rails, ejecutamos:
$ bin/rails generate scaffold Appointment name:string phone_number:string time:datetime
Esto le dice a nuestro generador que cree “scaffolding” (estructura) para un recurso llamado Appointment (Cita), que tiene las propiedades name, phone_number y time.
Ahora vamos al modelo que se generó y agregaremos algunas cosas.
Modelo de cita
El modelo de cita es bastante simple, pero dado que los humanos interactuarán con él, asegurémonos de añadir validación de datos.
Validación de datos
Las validaciones son importantes, ya que queremos asegurarnos de que solo se guarden datos precisos en nuestra base de datos. En este caso, solo queremos validar que todos nuestros campos obligatorios están presentes. Podemos hacerlo creando una afirmación validates
con presence: true
.
Es probable que una persona admin cree nuestro modelo de cita en el lugar de la cita. Bueno, sería genial que pudiéramos dar a nuestro usuario admin algunos comentarios cuando creen la cita. Afortunadamente, si añadimos validaciones a nuestros modelos en Rails obtenemos informes de errores gratis con el objeto flash
de la sesión.
Una nota: para ejecutar esta demostración necesitarás ejecutar rake db:migrate
la cual ejecutaría las migraciones en nuestra carpeta db/migrate. Para este tutorial nos centraremos en los conceptos principales, pero si quieres obtener más información sobre migraciones puedes leer la Guía de Rails sobre el tema.
Ahora estamos listos para pasar al nivel de controlador de la aplicación móvil, empezando por las rutas de solicitud HTTP que necesitaremos.
Rutas
En una aplicación de Rails, Resource Routing asigna de forma automática las capacidades CRUD de un recurso a su controlador. Como nuestra Appointment
es un recurso ActiveRecord, podemos decirle a Rails que queremos utilizar estas rutas, lo que nos ahorrará algunas líneas de código.
Esto significa que en esta única línea de código tenemos de forma automática una ruta appointment/new
que representará nuestro archivo appointment/new.html.erb
de forma automática.
Echemos un vistazo a este formulario.
Formulario de cita nuevo
Cuando creamos una cita nueva, necesitamos un nombre de invitado, un número de teléfono y una hora. Mediante el uso de la etiqueta form_for
de Rails podemos vincular el formulario al objeto de modelo. Esto generará la marca de HTML necesaria que creará una cita nueva en el envío.
Señalemos una etiqueta auxiliar específica que Rails nos brinda para formularios vinculados a modelos.
Fecha y hora
Una posible pérdida de tiempo es averiguar cómo gestionar la fecha y hora de la cita. En realidad, se trata de dos entradas de usuario independientes, una para el día y otra para la hora de la cita. Necesitamos una manera de combinar estas dos entradas separadas en un parámetro en el lado del servidor. Rails gestiona esto de nuevo dándonos las etiquetas data_select
y time_select
que el servidor reúne de forma automática en un parámetro que se asigna a la propiedad appointment.time
.
Volvamos al controlador para ver qué sucede cuando creamos esta cita.
Gestionar el formulario POST
Uno de los otros controladores prácticos creados por nuestra ruta de recursos Appointment
era appointment/create
que gestiona POST desde nuestro formulario.
En nuestro controlador tomamos la entrada de nuestro formulario y creamos un modelo Appointment
nuevo. Si la cita se guarda con éxito en la base de datos, redirigiremos a la vista de detalles de la cita, que mostrará al creador la cita nueva y le permitirá editarla o eliminarla.
A continuación, echaremos un vistazo a los controladores generados para editar y eliminar.
Interactuar con citas
Como usuario, deseo ver una lista de todas las citas futuras y poder eliminarlas.
Si eres una organización que gestiona muchas citas, es probable desees poder verlas y gestionarlas en una única interfaz. Eso es lo que abordaremos en esta historia de usuario. Crearemos una interfaz de usuario para:
- Mostrar todas las citas
- Eliminar las citas individuales
Empecemos por mirar el controlador.
Mostrar una lista de citas
En el nivel de controlador, todo lo que haremos es obtener una lista de todas las citas en la base de datos y las representaremos con una vista. También debemos añadir un aviso si no hay ninguna cita, ya que esta demostración depende de que haya al menos una cita en el futuro.
Volvamos a la plantilla para ver nuestra lista de citas.
Ver todas las citas
La vista de índice muestra todas las citas, que se ordenan de forma automática por date_created
. Lo único que necesitamos añadir para completar nuestra historia de usuario es un botón de eliminación. Añadiremos el botón de edición solo por diversión.
Helpers de URL
Puedes notar que en lugar de codificar las URL para editar y eliminar estamos usando un Helper de URL de Rails. Si ves la marca representada, verás estas rutas:
/appointments/
ID
/edit
para editar/appointments/
ID
para eliminar, con un método HTTP DELETE anexado a la consulta
Estos helpers de URL pueden tomar un objeto de cita o un ID.
Existen otros helpers en este código que Rails genera por nosotros. Lo que quiero señalar es la etiqueta :confirm
. La etiqueta confirm (confirmar) es un atributo de datos que interrumpe la solicitud DELETE
real con una alerta de javascript. Estas son las prácticas recomendadas para llamar a DELETE
en un objeto. Si el usuario confirma que procesamos la solicitud con normalidad, de lo contrario no se realizará ninguna acción.
Ahora veamos lo que sucede en el controlador cuando pedimos que se elimine una cita.
Buscar una cita
En este controlador necesitamos extraer un registro de cita y, a continuación, eliminarlo. Echemos un vistazo a cómo obtenemos la cita en primer lugar.
Puesto que es probable que necesitaremos un registro de cita en la mayoría de nuestras vistas, deberíamos crear un método de instancia privada que se pueda compartir entre varios controladores.
En set_appointment
utilizamos el parámetro de ID, que se transfiere desde la ruta, para buscar la cita. Luego en la parte superior de nuestro controlador usamos el filtro before_action
de la siguiente manera:
before_action :set_appointment, only: [:show, :edit, :update, :destroy]
Esto indica a nuestra aplicación móvil a qué controladores aplicar este filtro. En este caso, solo necesitamos una cita cuando el controlador se ocupa de una sola cita.
Ahora veamos lo que sucede cuando se elimina una cita.
Eliminar una cita
Ahora que tenemos la cita, solo tenemos que llamar a .destroy
. En una app de producción que te recomendamos evaluar si debes utilizar .delete
en lugar de destruir, ya que ambas son formas válidas de eliminar una fila de la base de datos en Rails. Para nuestros propósitos utilizaremos la destrucción menos eficaz por dos razones:
- Gestiona la limpieza de la base de datos
- Mantiene la
Appointment
en la memoria, de modo que podamos enviar un mensaje de éxito al usuario
Ahora que podemos interactuar con nuestras citas, vamos a dedicarnos al envío de recordatorios cuando se acerca una de estas citas.
Enviar el recordatorio
Como un sistema de citas, deseo notificar a un usuario mediante SMS en un intervalo arbitrario antes de una cita futura.
Existen muchas formas de crear esta parte de nuestra aplicación, pero no importa cómo la implementes, debe haber dos partes móviles:
- Una secuencia de comandos que comprueba la base de datos para cualquier cita próxima y, a continuación, envía un SMS
- Un trabajador que ejecuta esa secuencia de forma continua
Echemos un vistazo a cómo decidimos implementar este último con Delayed::Job
.
Trabajar con Delayed::Job
Como mencionamos antes, hay muchas maneras de implementar un planificador o trabajador, pero en Rails Delayed::Job
es el más establecido.
Delayed Job necesita una actividad en segundo plano de algún tipo para poner en cola los trabajos siguientes. Aquí hemos añadido el adaptador ActiveRecord para delayed_job, que utiliza nuestra base de datos a fin de almacenar la base de datos de 'Jobs'. Hay bastantes actividades en segundo plano soportadas, así que usa la gema correcta para tu aplicación móvil.
Una vez incluida la gema, necesitamos ejecutar bundle install
y ejecutar la tarea de Rake para crear la base de datos.
rails g delayed_job:active_record
Puedes ver todos estos pasos en el repositorio de Github para este proyecto.
Ahora estamos listos para crear el trabajo real.
Enviar un recordatorio
El siguiente paso para enviar un recordatorio a nuestro usuario es crear la secuencia de comandos que se activará en algún intervalo antes de la hora de la cita. Terminaremos deseando programar este recordatorio cuando se cree la cita, por lo que tiene sentido escribirlo como método en el modelo de cita.
Lo primero que hacemos es crear un Twilio Client que enviará nuestros SMS mediante la API REST de Twilio. Necesitaremos tres cosas para crear el Twilio Client:
- Nuestro SID de cuenta de Twilio
- Nuestro token de autenticación Twilio
- Un número de Twilio en nuestra cuenta que pueda enviar mensajes de texto
Todos estos elementos se encuentran en la consola.
Entonces lo que tenemos que hacer para enviar un SMS es utilizar messages.create()
incorporado a fin de enviar un SMS al teléfono del usuario.
Devolución de llamada de modelo
Como hicimos nuestra secuencia de comandos de recordatorio un método en el modelo, obtenemos una herramienta muy útil; una devolución de llamada. Cuando se usa la devolución de llamada before_create
nos aseguramos de que se llame al recordatorio siempre que se cree una cita.
El último paso es asegurarse de que Delayed Job siempre termine programando esta devolución de llamada.
Programar un recordatorio
Bueno, ya casi hemos terminado, ahora lo que tenemos que hacer es escribir un controlador de horarios extremadamente complicado que haga lo siguiente:
- Buscar cada cita futura
- Añadirla a una tabla de Jobs
- Comprobar si se encuentra dentro del intervalo
minutes_before_appointment
- Activar el método de recordatorio
Espera, Delayed Job hace esto de forma gratuita en un método práctico llamado handle_asynchronously
que le indica a Delayed Job que programe este trabajo siempre que se active este método. Puesto que nuestro tiempo de trabajo depende de la instance
de la cita individual, necesitamos transferir una función al método handle_asynchronously
que calculará el tiempo. En este caso, minutes_before_appointment
se establece en 30 minutos, pero puedes utilizar cualquier intervalo de Time
aquí.
Ahora, cuando creemos una cita, veremos una fila nueva en la tabla de Jobs, con una hora y un método que se deben activar. Además, delayed_job guarda los errores e intentos para que podamos depurar cualquier rareza antes de que falle. Una vez que activa un trabajo, lo elimina de la base de datos, por lo que en un buen día deberíamos ver una base de datos vacía.
Todo listo
Increíble, eso fue todo un trabajo, pero en realidad tuvimos que escribir muy poco código para obtener recordatorios de citas automáticos activados con Twilio.
¿Dónde ir a continuación?
Con un poco de código y una pizca de configuración, estamos listos para recibir recordatorios de citas automatizados en nuestra aplicación móvil. ¡Bien hecho!
Si eres un desarrollador de Ruby que trabaja con Twilio, puedes consultar otros tutoriales en Ruby:
Coloca un botón en tu página web que conecte a los visitantes con el servicio de asistencia en directo o con el personal de ventas por teléfono.
Autenticación de dos factores
Mejora la seguridad de la funcionalidad de inicio de sesión de la app Ruby al añadir autenticación de dos factores por mensajes de texto.
¿Te ayudó esto?
Gracias por consultar este tutorial. Si tienes algún comentario que compartir con nosotros, comunícate con nosotros en Twitter... nos encantaría saber lo que piensas y conocer lo que estás creando.
¿Necesitas ayuda?
Todos la necesitamos a veces; la programación es difícil. Obtén ayuda ahora de nuestro equipo de soporte, o recurre a la sabiduría de la multitud visitando Stack Overflow Collective de Twilio o navegando por la etiqueta de Twilio en Stack Overflow.