https://a.storyblok.com/f/270183/34045/4f8d2222f3/ruby-on-rails-actioncable.png

Criação de um aplicativo de chat para atendimento ao cliente com o Action Cable do Rails 5 e SMS

Publicado em May 13, 2021

Tempo de leitura: 10 minutos

O Rails 5 foi lançado com alguns novos recursos incríveis, como Turbolinks 5 e o modo API, mas o recurso que chamou nossa atenção foi a nova integração nativa com WebSocket no Action Cable. Essa nova abstração em torno do WebSocket está incorporada diretamente ao Rails e é perfeita para eventos em tempo real e comunicação bidirecional. Hoje vamos dar uma olhada em como construir uma experiência de atendimento ao cliente com base nela e na SMS API da Nexmo.

Um chat de atendimento ao cliente em Ruby on Rails 5

Neste tutorial, vamos criar um sistema de chat bidirecional de atendimento ao cliente para uma empresa que deseja se comunicar diretamente com seus clientes, não apenas pelo site, mas também por SMS. O aplicativo web servirá de interface para o “agente de atendimento ao cliente” e será desenvolvido com o Action Cable, enquanto os clientes poderão usar seus celulares para enviar mensagens de texto diretamente ao agente de atendimento.

Customer Service Chat with Rails 5 Action Cable and SMS

Para facilitar as coisas, criamos um ponto de partida para nosso aplicativo e o colocamos no GitHub. É um aplicativo básico em Rails 5 com um MessagesController para criar novas mensagens em um tópico. Fornecemos alguns dados fictícios por meio do arquivo seed e uma interface de usuário bonita com a ajuda do Semantic UI.

Certifique-se de ter o Ruby 2.2.2 ou uma versão superior instalada. Em seguida, você pode baixar o código inicial deste tutorial no GitHub, caso queira acompanhar a programação.

git clone git@github.com:nexmo-community/nexmo-customer-service-chat-demo.git cd nexmo-customer-service-chat-demo bundle install rails db:create db:migrate db:seed bundle exec rails server

Em seguida, acesse localhost:3000 no seu navegador e você poderá comentar nos tópicos existentes, mas nada será enviado por SMS por enquanto.

Todo o código para este ponto de partida pode ser encontrado no ramo no GitHub. Todo o código que adicionaremos a seguir pode ser encontrado no after . Para sua conveniência, você pode ver todas as alterações entre nosso ponto inicial e final no GitHub também.

SMS da Nexmo e Action Cable para Rails 5

A SMS API da Nexmo oferece baixa latência e alta taxa de entrega de mensagens, o que é ideal para o chat de atendimento ao cliente em tempo real. Analisaremos dois elementos principais: o envio e o recebimento de mensagens de texto e a exibição delas em tempo real no aplicativo web usando o Action Cable.

Para isso, vamos fazer as seguintes alterações em nosso aplicativo:

  • Ouvir mensagens de texto recebidas

  • Exibir uma nova mensagem em nossa interface do usuário com o Action Cable

  • Adicionar o Nexmo ao nosso aplicativo

  • Enviar novas mensagens por SMS a partir do agente de serviço (por meio da Nexmo)

Exibindo mensagens SMS recebidas com o Action Cable

Nosso primeiro passo será adicionar mensagens SMS recebidas ao nosso aplicativo. Para isso, precisaremos obter um número de telefone da Nexmo capaz de enviar e receber mensagens SMS.

Incoming Messages

Você pode comprar um número no Painel da Nexmoou usar o nexmo-cli e adquirir um diretamente pela linha de comando. Você pode encontrar suas credenciais de API na página de configurações da sua conta Nexmo

Por exemplo, para comprar um número de telefone do Reino Unido que comece com 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
4475555555555

Quando uma mensagem SMS for recebida nesse novo número, a Nexmo chamará a URL do webhook que especificarmos. Por enquanto, vamos criar um webhook fictício que apenas retorne uma resposta JSON simples.

# 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

Vamos acrescentar isso também à nossa routes.rb.

# config/routes.rb
Rails.application.routes.draw do
  resources :text_messages
  ...
end

Se você carregar agora localhost:3000/text_messages , você deverá ver uma resposta em JSON.

Para tornar seu aplicativo acessível publicamente pelos webhooks do Nexmo, você tem algumas opções. Se tiver a sorte de ter um IP público em sua máquina, você já está pronto para começar; para o resto de nós, podemos implantar o aplicativo, usar um túnel SSH ou minha solução favorita: usar o incrível ngrok .

Após a instalação, você pode obter uma URL pública da seguinte forma:

ngrok http 3000

Assim que seu aplicativo estiver disponível ao público, poderemos vincular nosso número a uma URL de webhook. A partir de então, sempre que for recebida uma mensagem SMS, será feita uma chamada para essa URL. Para isso, vamos usar novamente o nexmo-cli.

nexmo link:sms 44755555555 http://.ngrok.io/text_messages Number updated

Se ocorrer algum erro nesta etapa, verifique se você está usando o número de telefone da Nexmo cadastrado na sua Account e se a URL do webhook está acessível ao público.

O próximo passo é ampliar nossa ação para receber a mensagem, analisar a resposta e salvá-la em nosso banco de dados.

# 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

Experimente! Inicie seu servidor (e o ngrok, se necessário) e envie uma mensagem para o seu número da Nexmo. Em poucos segundos, a mensagem deve ser processada pelo seu aplicativo. Atualize a página para ver sua nova mensagem.

Exibindo mensagens com o Action Cable

Obviamente, não queremos ter que atualizar a página toda vez que chega uma nova mensagem, e é exatamente aí que o Action Cable entra em cena.

A Action Cable utiliza canais para a comunicação entre editores e assinantes. No nosso caso, vamos enviar o number e o html da nossa nova mensagem no messages canal.

Vamos começar adicionando uma nova linha ao nosso TextMessagesController:

# app/controllers/text_messages_controller.rb
def create_message(params)
  ...
  send_cable(message)
  render json: { state: 200 }
end

Como você pode ver, separamos nossa publicação em um método auxiliar, já que vamos querer reutilizá-la mais tarde.

Nosso helper é bem simples — ele gera o HTML e, em seguida, passa o HTML e o número para o ActionCable.server.broadcast 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 }
  })
end

Para receber a mensagem no front-end, precisaremos nos conectar ao nosso servidor por meio de um novo WebSocket e ficar à escuta no messages canal para detectar novas mensagens que cheguem.

Começamos montando ActionCable em nossas rotas.

# config/routes.rb
Rails.application.routes.draw do
  mount ActionCable.server => '/cable'
  ...
end

Isso disponibilizará um ponto de conexão WebSocket em http://localhost:3000/cable ao qual podemos nos conectar usando nosso JavaScript da seguinte maneira.

// app/assets/javascripts/channels/messages.js
App.cable.subscriptions.create('MessagesChannel', {
  received: function(data) {
    // process data
  }
});

Então, como o Rails sabe que os MessagesChannel corresponde ao messages fluxo? Ele não sabe. Precisamos especificar isso nós mesmos.

# app/channels/messages_channel.rb
class MessagesChannel < ApplicationCable::Channel
  def subscribed
    stream_from "messages"
  end
end

Em exemplos mais complexos, você poderia criar dinamicamente o nome do canal com base no usuário autenticado, em parâmetros adicionais e muito mais. No nosso exemplo, estamos mantendo as coisas simples e apenas definindo de forma estática uma assinatura do messages stream.

Por fim, precisamos atualizar nosso código JavaScript para inserir o HTML que recebemos pelo cabo em nossa interface de usuário.

// 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');
  }
});

Esse código faz algumas coisas. Primeiro, ele localiza o .thread e .numbers elementos dentro do DOM. Em seguida, se estivermos visualizando mensagens (na views/messages/show.html.erb visualização) correspondente ao número de origem da mensagem recebida, colocamos a mensagem no início. Se estivermos na index visualização (views/messages/index.html.erb), exibindo a mensagem mais recente de todos os Numbers, substituímos os detalhes da mensagem existente pelo novo código HTML.

Para que tudo isso funcione, precisamos adicionar um data-number atributo ao .thread elemento e a cada .message elemento, para que possamos saber a qual número eles estão 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 %>

É isso aí sobre o Action Cable! Inicie seu servidor (e o ngrok, se necessário) e envie uma mensagem para o seu número Nexmo. Em poucos segundos, a mensagem deve ser processada pelo seu aplicativo e, desta vez, você não precisa atualizar a página para ver a nova mensagem. Em vez disso, ela aparecerá assim que o Action Cable a publicar no messages fluxo.

Responder a mensagens

Agora que já temos o recebimento de SMS funcionando, vamos atualizar nosso código atual para enviar novas mensagens do agente de atendimento diretamente para o número de telefone do cliente.

Incoming Messages

Para enviar uma mensagem SMS pelo Nexmo, precisaremos adicionar o nexmo gem ao projeto.

# Gemfile
gem 'nexmo'

group :development, :test do
  gem 'dotenv-rails'
end

Como você pode ver, também adicionamos o dotenv-rails gem. Isso serve apenas para facilitar as coisas, pois permitirá que o aplicativo carregue nossas credenciais de API a partir de um .env arquivo. A nexmo gem detecta automaticamente essas variáveis de ambiente e as utiliza para inicializar o cliente. Você pode encontrar suas credenciais na página de configurações da sua conta Nexmo.

# .env
NEXMO_API_KEY=<your_api_key>
NEXMO_API_SECRET=<your_api_secret>
NEXMO_NUMBER=<your_nexmo_number>

Também adicionamos o nosso NEXMO_NUMBER ao .env arquivo aqui também.

A seguir, vamos transformar nosso novo formulário de mensagem em um remote formulário e usar ActionCable para mostrar ao cliente os novos envios, em vez de redirecionar a página.

<!-- app/views/messages/_form.html.erb -->
<%= form_for(@new_message, remote: true, html: { class: 'ui form error' }) do |f| %>

Em nosso controlador, vamos substituir o redirecionamento por algo mais familiar.

# app/controllers/messages_controller.rb
if message.save
  send_cable(message)
  send_sms(message)
end

O send_cable é o nosso editor do Action Cable de antes, e o send_sms será implementado em seguida.

Antes de continuarmos, porém, vamos criar uma create.js.erb para que nossa ação não gere erros por falta de uma visualização. Usaremos essa visualização também para limpar nosso textarea quando o formulário for enviado.

# app/views/messages/create.js.erb
$('textarea').val('');

Por fim, vamos enviar o SMS para o número correto com a mensagem do agente de atendimento ao 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
  )
end

É isso aí, agora você já deve ter uma integração completa de mensagens SMS bidirecionais com o Rails, com a ajuda do Nexmo e do Action Cable do Rails 5. Reinicie o servidor, se necessário, e envie algumas mensagens para si mesmo para ver tudo funcionando.

Próximos passos

Obviamente, deixamos de fora muitas coisas legais, tanto no Action Cable quanto na SMS API da Nexmo. Não fizemos a autenticação do agente de atendimento ao cliente e não fornecemos uma interface de usuário web para o cliente — o que seria interessante desenvolver com base na API Nexmo Verify , como fizemos na postagem sobre Autenticação de Dois Fatores (2FA) no Ruby on Rails com Devise e Nexmo Verify.

Vou experimentar o o Turbolinks 5 para ver se consigo transformar isso em uma experiência nativa para dispositivos móveis. Adoraria saber o que vocês acrescentariam a seguir. Mandem um tweet para mim (meu nome de usuário é @cbetta) com suas opiniões e ideias.

Compartilhar:

https://a.storyblok.com/f/270183/400x400/73e68604be/phil-leggetter.jpg
Phil Leggetter

Phil is Head of Developer Relations at Hookdeck, an asynchronous messaging platform, and a proud Vonage alumni.