
Partager:
Phil is Head of Developer Relations at Hookdeck, an asynchronous messaging platform, and a proud Vonage alumni.
Construire une application de chat pour le service client avec Rails 5 Action Cable et SMS
Rails 5 a été livré avec de nouvelles fonctionnalités étonnantes telles que Turbolinks 5 et le mode API, mais la fonctionnalité qui a attiré notre attention est la nouvelle intégration de WebSocket avec Action Cable. Cette nouvelle abstraction autour de WebSocket est intégrée directement dans Rails et est parfaite pour les événements en temps réel et la communication bidirectionnelle. Aujourd'hui, nous allons nous pencher sur la construction d'une expérience de service client à partir de cette abstraction et de l'API Nexmo SMS API.
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.
Un chat pour le service client en Ruby on Rails 5
Pour ce tutoriel, nous allons créer un système de chat bidirectionnel pour l'assistance à la clientèle pour une entreprise qui souhaite communiquer directement avec ses clients, non seulement via son site, mais aussi par SMS. L'application web sera l'interface de "l'agent de support client" et sera alimentée par Action Cable, tandis que les clients pourront utiliser leur téléphone pour envoyer des messages texte directement à l'agent de support.

Pour faciliter les choses, nous construisons un point de départ pour notre application et la mettons sur Github. Il s'agit d'une application Rails 5 de base avec une fonction MessagesController pour créer de nouveaux messages dans un thread. Nous avons fourni quelques fausses données via le fichier de départ et une jolie interface utilisateur avec l'aide de Semantic UI.
Assurez-vous d'avoir installé Ruby 2.2.2 ou une version plus récente. Vous pouvez ensuite télécharger le point de départ de ce tutoriel sur GitHub si vous souhaitez coder.
Visitez ensuite localhost:3000 dans votre navigateur et vous devriez pouvoir commenter les fils de discussion existants, mais rien ne sera envoyé par SMS pour l'instant.
Tout le code de ce point de départ se trouve sur la page before sur Github. Tout le code que nous ajouterons ci-dessous se trouve sur la branche after sur Github. Pour votre commodité, vous pouvez voir tous les changements entre notre point de départ et notre point d'arrivée sur Github.
Nexmo SMS et Rails 5 Action Cable
L'API Nexmo SMS API Nexmo vous permet d'envoyer des messages à faible latence et à haut débit, ce qui convient parfaitement au chat en temps réel du service client. Nous allons nous pencher sur deux éléments essentiels : l'envoi et la réception de messages texte et leur affichage en direct dans l'application Web à l'aide d'Action Cable.
Pour ce faire, nous allons apporter les modifications suivantes à notre application :
Écouter les messages texte entrants
Afficher un nouveau message dans notre interface utilisateur avec Action Cable
Ajouter Nexmo à notre application
Diffusion de nouveaux messages par SMS depuis l'agent de service (via Nexmo)
Afficher les SMS entrants avec Action Cable
Notre première étape consistera à ajouter des messages SMS entrants à notre application. Pour ce faire, nous devrons mettre la main sur un numéro de téléphone Numbers capable d'envoyer et de recevoir des SMS.

Vous pouvez acheter un numéro à partir du tableau de bord Nexmoou vous pouvez utiliser le logiciel nexmo-cli et en acheter un directement à partir de la ligne de commande. Vous pouvez trouver vos identifiants API sur la page des paramètres de votre Account Nexmo
Par exemple, pour acheter un numéro de téléphone britannique commençant par 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
4475555555555Lorsqu'un SMS est reçu par ce nouveau numéro, Numbers appelle l'URL webhook que nous avons spécifiée. Pour l'instant, nous allons créer un webhook fictif qui renvoie une simple réponse JSON.
# 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
Ajoutons également ceci à notre routes.rb.
# config/routes.rb
Rails.application.routes.draw do
resources :text_messages
...
endSi vous chargez maintenant localhost:3000/text_messages vous devriez voir une réponse JSON.
Pour rendre votre application publiquement accessible par les webhooks Nexmo, vous avez plusieurs options. Si vous avez la chance d'avoir une IP publique sur votre machine, vous devriez être prêt à partir. Pour les autres, nous pouvons déployer l'application, utiliser un tunnel SSH, ou ma solution préférée : utiliser l'incroyable logiciel ngrok qui est un outil extraordinaire.
Une fois installé, vous pouvez obtenir une URL publique en utilisant :
Une fois que votre application est accessible au public, nous pouvons lier notre numéro à une URL webhook. Désormais, à chaque fois qu'un SMS sera reçu, un appel sera effectué vers cette URL. Pour cela, nous utilisons à nouveau l'élément nexmo-cli.
Si vous obtenez des erreurs à ce stade, assurez-vous que vous utilisez le numéro de téléphone Nexmo de votre Account et que l'URL du webhook est accessible au public.
L'étape suivante consiste à développer notre action pour qu'elle prenne en compte le message entrant, analyse la réponse et l'enregistre dans notre base de données.
# 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 }
endEssayez ! Démarrez votre serveur (et ngrok si nécessaire) et envoyez un message à votre numéro Nexmo. En quelques secondes, le message devrait être analysé par votre application. Rafraîchissez le site web pour voir votre nouveau message.
Afficher les messages avec Action Cable
Il est évident que nous ne voulons pas avoir à rafraîchir notre page à chaque fois qu'un nouveau message arrive et c'est exactement là qu'intervient Action Cable.
Action Cable utilise canaux pour communiquer entre les éditeurs et les abonnés. Dans notre cas, nous allons envoyer l'action number et le html de notre nouveau message sur le canal messages sur le canal
Nous commencerons par ajouter une nouvelle ligne à notre fichier TextMessagesController:
# app/controllers/text_messages_controller.rb
def create_message(params)
...
send_cable(message)
render json: { state: 200 }
endComme vous pouvez le voir, nous avons extrait notre publication dans une méthode d'aide, car nous voudrons la réutiliser plus tard.
Notre aide est assez simple - elle rend le HTML et transmet le HTML et le nombre à la méthode ActionCable.server.broadcast à la méthode
# 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 }
})
endAfin de recevoir le message sur le front-end, nous devons nous connecter à notre serveur via une nouvelle WebSocket et écouter le canal messages pour les nouveaux messages qui arrivent.
Nous commençons par monter ActionCable dans nos itinéraires.
# config/routes.rb
Rails.application.routes.draw do
mount ActionCable.server => '/cable'
...
end
Cela exposera un point de terminaison WebSocket sur http://localhost:3000/cable auquel nous pourrons nous connecter en utilisant notre Javascript comme suit.
// app/assets/javascripts/channels/messages.js
App.cable.subscriptions.create('MessagesChannel', {
received: function(data) {
// process data
}
});Alors comment Rails sait-il que l'élément MessagesChannel correspond au flux messages ? Il ne le sait pas. Nous devons le spécifier nous-mêmes.
# app/channels/messages_channel.rb
class MessagesChannel < ApplicationCable::Channel
def subscribed
stream_from "messages"
end
end
Dans des exemples plus complexes, vous pourriez créer dynamiquement le nom du canal en fonction de l'utilisateur authentifié, de paramètres supplémentaires, et bien plus encore. Dans notre exemple, nous restons simples et nous nous contentons de coder en dur un abonnement au flux messages stream.
Enfin, nous devons mettre à jour notre JS pour insérer dans notre interface utilisateur le code HTML que nous avons reçu par le biais du câble.
// 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');
}
});
Ce code fait plusieurs choses. Tout d'abord, il trouve les .thread et .numbers dans le DOM. Ensuite, si nous visualisons des messages (dans la vue views/messages/show.html.erb ), nous ajoutons le numéro du message entrant au message. Si nous sommes dans la vue index vue (views/messages/index.html.erb), qui affiche le dernier message de tous les Numbers, nous remplaçons les détails du message existant par le nouveau code HTML.
Pour que tout cela fonctionne, nous devons ajouter un attribut data-number à l'élément .thread et à chaque élément .message afin de savoir à quel numéro ils se rapportent.
<!-- 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 %>
C'est tout pour Action Cable ! Démarrez votre serveur (et ngrok si nécessaire) et envoyez un message à votre numéro Numbers. En quelques secondes, le message devrait être analysé par votre application et cette fois, vous n'avez pas besoin de rafraîchir le site web pour voir votre nouveau message. Il apparaîtra dès qu'Action Cable le publiera dans le messages flux.
Répondre aux messages
Maintenant que les SMS entrants fonctionnent, mettons à jour notre code existant pour envoyer les nouveaux messages de l'agent de service directement au numéro de téléphone du client.

Afin d'envoyer un SMS via Nexmo, nous allons devoir ajouter la gemme nexmo au projet.
# Gemfile
gem 'nexmo'
group :development, :test do
gem 'dotenv-rails'
endComme vous pouvez le voir, nous avons également ajouté la dotenv-rails gem. C'est juste pour faciliter les choses car cela permettra à l'application de charger nos identifiants API à partir d'un fichier .env fichier. La gem nexmo récupère automatiquement ces variables d'environnement et les utilise pour initialiser le client. Vous pouvez trouver vos identifiants sur la page des paramètres de votre Account Nexmo.
# .env
NEXMO_API_KEY=<your_api_key>
NEXMO_API_SECRET=<your_api_secret>
NEXMO_NUMBER=<your_nexmo_number>Nous avons également ajouté notre NEXMO_NUMBER au fichier .env ici aussi.
Ensuite, transformons notre nouveau formulaire de message en un formulaire remote et utilisons ActionCable pour montrer au client les nouvelles soumissions au lieu de rediriger la page.
<!-- app/views/messages/_form.html.erb -->
<%= form_for(@new_message, remote: true, html: { class: 'ui form error' }) do |f| %>
Dans notre contrôleur, nous remplacerons la redirection par quelque chose de familier.
# app/controllers/messages_controller.rb
if message.save
send_cable(message)
send_sms(message)
endLe send_cable est notre éditeur de câble d'action de tout à l'heure, et l'élément send_sms sera implémenté ensuite.
Avant de continuer, créons un create.js.erb afin que notre action ne se plaigne pas d'une vue manquante. Nous utiliserons cette vue pour effacer notre textarea lorsque le formulaire sera soumis.
# app/views/messages/create.js.erb
$('textarea').val('');Enfin, envoyons le SMS au bon numéro avec le message de l'agent du service clientèle.
# app/helpers/application_helper.rb
def send_sms message
Nexmo::Client.new.send_message(
from: ENV['NEXMO_NUMBER'],
to: message.number,
text: message.text
)
endVoilà, vous devriez maintenant avoir une messagerie bidirectionnelle SMS vers Rails en place avec l'aide de Nexmo et de l'Action Cable de Rails 5. Redémarrez votre serveur si nécessaire et envoyez-vous des messages pour voir ce que cela donne.
Prochaines étapes
Il est évident que nous avons omis beaucoup de choses intéressantes dans Action Cable et dans l'API SMS de Nexmo. Nexmo SMS API. Nous n'avons pas authentifié l'agent du service clientèle, et nous n'avons pas fourni d'interface web pour le client - ce qui serait intéressant de construire au-dessus de l Nexmo Verify API comme nous l'avons fait avec l'article sur l'authentification à deux facteurs (2F). Authentification à deux facteurs (2FA) en Ruby on Rails avec Devise et Nexmo Verify.
Je jouerai avec Turbolinks 5 pour voir si je peux en faire une expérience mobile native. J'aimerais savoir ce que vous ajouteriez ensuite ? N'hésitez pas à m'envoyer un tweet (je suis @cbetta) pour me faire part de vos réflexions et de vos idées.
