
Compartir:
Phil is Head of Developer Relations at Hookdeck, an asynchronous messaging platform, and a proud Vonage alumni.
Creación de una aplicación de chat de atención al cliente con Rails 5 Action Cable y SMS
Rails 5 incluye algunas novedades increíbles como Turbolinks 5 y el modo API, pero lo que más nos ha llamado la atención es la nueva integración de WebSocket con Cable de acción. Esta nueva abstracción en torno a WebSocket está integrada directamente en Rails y es perfecta para eventos en tiempo real y comunicación bidireccional. Hoy vamos a echar un vistazo a la construcción de una experiencia de servicio al cliente en la parte superior de la misma y el SMS API de Nexmo.
Vonage API Account
To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.
This tutorial also uses a virtual phone number. To purchase one, go to Numbers > Buy Numbers and search for one that meets your needs.
Chat de atención al cliente en Ruby on Rails 5
En este tutorial crearemos un sistema de chat bidireccional de atención al cliente para una empresa que quiere comunicarse directamente con sus clientes no sólo a través de su sitio, sino también a través de SMS. La aplicación web será la interfaz para el "agente de atención al cliente" y será impulsado por Action Cable, mientras que los clientes pueden utilizar su teléfono para enviar mensajes de texto directamente al agente de soporte.

Para facilitar las cosas, creamos un punto de partida para nuestra aplicación y lo ponemos en Github. Es una aplicación Rails 5 básica con un botón MessagesController para crear nuevos mensajes en un hilo. Proporcionamos algunos datos falsos a través del archivo semilla y una bonita interfaz de usuario con la ayuda de Interfaz semántica.
Asegúrate de tener instalado Ruby 2.2.2 o superior. A continuación, puede descargar el punto de partida de este tutorial desde GitHub si desea codificar a lo largo.
A continuación, visite localhost:3000 en tu navegador y deberías poder comentar en los hilos existentes, pero todavía no se enviará nada por SMS.
Todo el código de este punto de partida se encuentra en la página antes de en Github. Todo el código que añadiremos a continuación se encuentra en la rama después de rama. Para tu comodidad puedes ver todos los cambios entre nuestro punto inicial y final en Github también.
Nexmo SMS y Rails Cable de 5 acciones
El sitio SMS API de Nexmo le proporciona una mensajería de baja latencia y alta capacidad de entrega que se adapta perfectamente al chat de atención al cliente en tiempo real. Veremos dos elementos principales: enviar y recibir mensajes de texto y mostrarlos en directo en la aplicación web mediante Action Cable.
Para ello vamos a realizar los siguientes cambios en nuestra aplicación:
Escuchar los mensajes de texto entrantes
Mostrar nuevo mensaje en nuestra UI con Action Cable
Añadir Nexmo a nuestra aplicación
Difusión de nuevos mensajes por SMS desde el agente de servicio (a través de Nexmo)
Mostrar mensajes SMS entrantes con Action Cable
Nuestro primer paso será añadir mensajes SMS entrantes a nuestra aplicación. Para ello tendremos que hacernos con un número de teléfono Nexmo capaz de enviar y recibir mensajes SMS.

Puede comprar un número en el Panel Nexmoo puede utilizar la aplicación nexmo-cli y comprar uno directamente desde la línea de comandos. Puedes encontrar tus credenciales API en la página de configuración de su cuenta Nexmo
Por ejemplo, para comprar un número de teléfono del Reino Unido que empiece por 07:
> npm install -g nexmo-cli
> nexmo setup <your_api_key> <your_api_secret>
> nexmo number:buy GB 447* --confirm
Number purchased
> nexmo number:list
4475555555555Cuando este nuevo número reciba un SMS, Nexmo llamará a la URL del webhook que especifiquemos. Vamos a crear un webhook ficticio por ahora que sólo devuelve una respuesta JSON simple.
# app/controllers/text_messages_controller.rb
class TextMessagesController < ApplicationController
include ApplicationHelper
skip_before_action :verify_authenticity_token, :only => [:create]
# If webhooks are set up as GET requests
def index
render json: { state: 200 }
end
# If webhooks are set up as POST requests
def create
render json: { state: 200 }
end
end
Añadámoslo también a nuestro routes.rb.
# config/routes.rb
Rails.application.routes.draw do
resources :text_messages
...
endSi ahora carga localhost:3000/text_messages debería ver una respuesta JSON.
Para hacer tu aplicación públicamente accesible por los webhooks de Nexmo tienes algunas opciones. Si tienes la suerte de tener una IP pública en tu máquina deberías estar listo para ir, para el resto de nosotros podríamos desplegar la aplicación, utilizar un túnel SSH, o mi solución favorita: utilizar el increíble ngrok herramienta.
Una vez instalado puedes obtener una URL pública usando:
Una vez que tu aplicación esté disponible públicamente, podemos vincular nuestro número a una URL webhook. Ahora, cada vez que se reciba un SMS, se realizará una llamada a esta URL. Para ello volvemos a utilizar el método nexmo-cli.
Si se produce algún error en este estado, asegúrese de que está utilizando el número de teléfono Nexmo de su Account y de que la URL del webhook es de acceso público.
El siguiente paso es expandir nuestra acción para tomar el mensaje entrante, analizar la respuesta y guardarla en nuestra base de datos.
# app/controllers/text_messages_controller.rb
# If webhooks are set up as GET requests
def index
create_message(params)
end
# If webhooks are set up as POST requests
def create
create_message(params)
end
def create_message(params)
message = Message.create!(
number: params[:msisdn],
text: params[:text],
inbound: true
)
render json: { state: 200 }
end¡Pruébalo! Inicie su servidor (y ngrok si es necesario) y envíe un mensaje a su número Nexmo. En unos pocos segundos el mensaje debe ser analizado por su aplicación. Actualice el sitio web para ver su nuevo mensaje.
Mostrando mensajes con Acción Cable
Obviamente, no queremos tener que actualizar nuestra página cada vez que llegue un nuevo mensaje y aquí es exactamente donde entra en juego Action Cable.
Action Cable utiliza canales para comunicarse entre editores y suscriptores. En nuestro caso vamos a enviar el number y el html de nuestro nuevo mensaje en el messages canal.
Empezaremos añadiendo una nueva línea a nuestro fichero TextMessagesController:
# app/controllers/text_messages_controller.rb
def create_message(params)
...
send_cable(message)
render json: { state: 200 }
endComo puedes ver hemos extraído nuestra publicación en un método helper ya que querremos reutilizarlo más adelante.
Nuestro helper es bastante sencillo - renderiza el HTML y luego pasa el HTML y el número al método ActionCable.server.broadcast al método
# app/helpers/application_helper.rb
def send_cable message
html = render_message(message)
ActionCable.server.broadcast 'messages',
number: message.number,
html: html
end
def render_message message
ApplicationController.render({
partial: 'messages/message',
locals: { message: message }
})
endPara recibir el mensaje en el front-end querremos conectarnos a nuestro servidor a través de un nuevo WebSocket y escuchar el canal messages para recibir nuevos mensajes.
Empezamos montando ActionCable en nuestras rutas.
# config/routes.rb
Rails.application.routes.draw do
mount ActionCable.server => '/cable'
...
end
Esto expondrá un endpoint WebSocket en http://localhost:3000/cable al que podemos conectarnos usando nuestro Javascript como se indica a continuación.
// app/assets/javascripts/channels/messages.js
App.cable.subscriptions.create('MessagesChannel', {
received: function(data) {
// process data
}
});Entonces, ¿cómo sabe Rails que la directiva MessagesChannel mapea al messages stream? No lo sabe. Tenemos que especificarlo nosotros.
# app/channels/messages_channel.rb
class MessagesChannel < ApplicationCable::Channel
def subscribed
stream_from "messages"
end
end
En ejemplos más complicados podrías crear dinámicamente el nombre del canal basado en el usuario autenticado, parámetros extra, y mucho más. En nuestro ejemplo vamos a mantenerlo simple y sólo hard-coding una suscripción a la messages flujo.
Por último, tenemos que actualizar nuestro JS para insertar el HTML que recibimos a través del cable en nuestra interfaz de usuario.
// app/assets/javascripts/channels/messages.js
App.cable.subscriptions.create('MessagesChannel', {
received: function(data) {
var list = $('.numbers');
var thread = $('.thread');
var number = thread.data('number');
var latest = $('.message[data-number="'+data.number+'"]');
// prepend to message thread
if (thread.length &&
data.number == number) thread.prepend(data.html);
// prepend to list of ongoing threads
if (list.length) {
latest.remove();
list.prepend(data.html);
}
$('.message:first').transition('flash');
}
});
Este código hace varias cosas. En primer lugar, encuentra los archivos .thread y .numbers dentro del DOM. Luego, si estamos viendo mensajes (en la vista views/messages/show.html.erb vista) para el número que el mensaje entrante se ha recibido a partir de añadimos el mensaje. Si estamos en la index vista (views/messages/index.html.erb), mostrando el último mensaje de todos los números, reemplazamos los detalles del mensaje existente con el nuevo HTML.
Para que todo esto funcione necesitamos añadir un atributo data-number al elemento .thread y a cada elemento .message para saber con qué número están relacionados.
<!-- app/views/messages/show.html.erb -->
<div class="ui one cards thread" data-number="<%= params[:id] %>">
<!-- app/views/messages/_message.html.erb -->
<%= link_to "/messages/#{message.number}",
class: 'ui card message',
data: { number: message.number } do %>
¡Eso es todo para Action Cable! Inicia tu servidor (y ngrok si es necesario) y envía un mensaje a tu número Nexmo. En unos pocos segundos el mensaje debe ser analizado por su aplicación y esta vez no es necesario actualizar el sitio web para ver su nuevo mensaje. En su lugar, aparecerá tan pronto como Action Cable lo publique en el messages stream.
Responder a los mensajes
Así que ahora que tenemos SMS entrantes trabajando vamos a actualizar nuestro código existente para enviar nuevos mensajes desde el agente de servicio directamente al número de teléfono del cliente.

Para enviar un mensaje SMS a través de Nexmo vamos a tener que añadir la gema nexmo al proyecto.
# Gemfile
gem 'nexmo'
group :development, :test do
gem 'dotenv-rails'
endComo puede ver, también hemos añadido la gema dotenv-rails gema. Esto es sólo para hacer las cosas más fáciles, ya que permitirá que la aplicación cargue nuestras credenciales de la API desde un archivo .env archivo. La gema nexmo recoge automáticamente esas variables de entorno y las utiliza para inicializar el cliente. Puedes encontrar tus credenciales en la página de configuración de su cuenta Nexmo.
# .env
NEXMO_API_KEY=<your_api_key>
NEXMO_API_SECRET=<your_api_secret>
NEXMO_NUMBER=<your_nexmo_number>También hemos añadido nuestro NEXMO_NUMBER al archivo .env archivo aquí también.
A continuación vamos a convertir nuestro nuevo formulario de mensajes en un formulario remote y utilicemos ActionCable para mostrar al cliente los nuevos envíos en lugar de redirigir la página.
<!-- app/views/messages/_form.html.erb -->
<%= form_for(@new_message, remote: true, html: { class: 'ui form error' }) do |f| %>
En nuestro controlador sustituiremos la redirección por algo familiar.
# app/controllers/messages_controller.rb
if message.save
send_cable(message)
send_sms(message)
endEl send_cable es nuestro editor Action Cable de antes, y el send_sms se implementará a continuación.
Antes de continuar vamos a crear un create.js.erb para que nuestra acción no se queje de que falta una vista. Utilizaremos esta vista para borrar también nuestra vista textarea cuando se envíe el formulario.
# app/views/messages/create.js.erb
$('textarea').val('');Por último, enviemos el SMS al número correcto con el mensaje del agente de atención al cliente.
# app/helpers/application_helper.rb
def send_sms message
Nexmo::Client.new.send_message(
from: ENV['NEXMO_NUMBER'],
to: message.number,
text: message.text
)
endEso es todo, ahora deberías tener una mensajería SMS a Rails completa y bidireccional con la ayuda de Nexmo y el Action Cable de Rails 5. Reinicia tu servidor si es necesario y envíate algunos mensajes para verlo todo en acción.
Próximos pasos
Obviamente nos hemos saltado muchas cosas interesantes tanto en Action Cable como en la Nexmo SMS API. No hemos autenticado el agente de servicio al cliente, y no proporcionamos una interfaz de usuario web para el cliente - que sería interesante construir en la parte superior de la Nexmo Verify API como hicimos con el post sobre Autenticación de dos factores (2FA) en Ruby on Rails con Devise y Nexmo Verify.
Jugaré con Turbolinks 5 para ver si puedo convertirlo en una experiencia móvil nativa. Me encantaría saber qué añadirías tú a continuación. Envíame un tweet (soy @cbetta) con tus pensamientos e ideas.
