0

Ứng dụng Chat với Rails 5 Action Cable và Nexmo SMS API

Một số tính năng mới nổi bật trong Rails 5 như Turbolinks 5API mode, nhưng thú vị nhất là tích hợp sẵn WebSocket với Action Cable. Tính năng này giúp xây dựng các ứng dụng real-time hoàn hảo theo chuẩn Rails. Để demo, chúng ta sẽ xây dựng một ứng dụng chat real-time kết hợp Action Cable và Nexmo SMS API.

Giới thiệu

Ứng dụng chat giúp công ty liên lạc trực tiếp với khách hàng của họ, không chỉ qua web mà còn qua SMS. Web sẽ là "trung tâm hỗ trợ khách hàng" xây dựng bởi Action Cable, trong khi khách hàng có thể sử dụng điện thoại để gửi tin nhắn văn bản đến thẳng trung tâm hỗ trợ.

Tải về phần khởi tạo trên Github:

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

Đơn giản với một MessagesController để tạo tin nhắn mới cho từng chủ đề, dữ liệu fake tạo bằng seed file và giao diện Semantic UI đẹp. Cần cài đặt Ruby 2.2.2 trở lên để sử dụng Rails 5.

Sau đó vào localhost: 3000 và đã có thể bình luận về các chủ đề hiện có, nhưng hiện tại chưa gửi được SMS.

Mã nguồn phần khởi tạo này có trên nhánh before. Phần được thêm vào dưới đây sẽ ở nhánh after. Bạn có thể theo dõi những thay đổi tại đây.

Nexmo SMS và Rails 5 Action Cable

Nexmo SMS API có độ trễ thấp phù hợp trò chuyện theo thời gian thực. Xét hai yếu tố chính: gửi và nhận tin nhắn văn bản và hiển thị trực tiếp trong ứng dụng web sử dụng Action Cable.

Cần thực hiện các bước sau:

  • Nhận tin nhắn
  • Hiển thị tin nhắn trên web với Action Cable
  • Thêm Nexmo vào ứng dụng
  • Gửi tin nhắn mới thông qua Nexmo

Hiển thị tin nhắn đến

Đầu tiên là thêm các tin nhắn SMS gửi đến. Cần có một số điện thoại của Nexmo có khả năng gửi và nhận tin nhắn SMS.

img2

Bạn có thể mua từ Nexmo Dashboard, hoặc sử dụng thư viện nexmo-cli và lấy số từ command line. Chứng chỉ API có trên trang cài đặt tài khoản Nexmo.

Ví dụ: để mua số điện thoại ở Anh có đầu 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

Khi nhận một tin nhắn SMS, Nexmo gọi URL webhook chỉ định. Bây giờ, sẽ tạo một webhook giả để chỉ trả về mẫu JSON đơn giản.

# 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

Trong routes.rb.

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

Bây giờ vào localhost:3000/text_messages, bạn sẽ thấy phản hồi JSON.

Để làm cho ứng dụng của bạn có thể truy cập công khai bởi các webhook Nexmo, có một vài lựa chọn. Nếu bạn may mắn có một public IP, bạn đã sẵn sàng, nếu không chúng tôi có thể sử dụng SSH hoặc công cụ ngrok tuyệt vời.

Sau khi cài đặt, bạn có thể nhận được một URL bằng cách sử dụng:

ngrok http 3000

Khi ứng dụng công khai, có thể liên kết số điện thoại với một URL webhook. Bây giờ mỗi lần nhận tin nhắn SMS sẽ gọi đến URL này. Lại sử dụng nexmo-cli.

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

Nếu chẳng may có lỗi, hãy đảm bảo bạn đang sử dụng số điện thoại Nexmo trong tài khoản của mình và URL web có thể truy cập công cộng.

Bước tiếp theo là lấy SMS đến, phân tích câu trả lời và lưu nó vào cơ sở dữ liệu.

# 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

Hãy thử ! Bắt đầu máy chủ (và ngrok nếu cần) và gửi tin nhắn tới số Nexmo của bạn. Trong vòng vài giây, ứng dụng sẽ đươcj xử lý xong. Refresh trang để xem tin nhắn mới.

Thật phiền khi phải làm mới trang mỗi khi một tin nhắn mới đến và điều này được giải quyết với Action Cable.

Action Cable sử dụng các kênh để liên lạc giữa người gửi và người nhận. Trong trường hợp này, sẽ gửi số và html của tin nhắn mới trên kênh tin nhắn.

Chúng ta sẽ bắt đầu bằng cách thêm một dòng mới vào TextMessagesController:

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

Method hoạt động khá đơn giản - nó cho phép HTML và sau đó chuyển HTML và số sang phương thức ActionCable.server.broadcast.

# 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

Để nhận được thông báo trên giao diện người dùng, chúng ta sẽ kết nối với máy chủ qua một WebSocket mới và lắng nghe các kênh để gửi tin nhắn mới.

Chúng tôi bắt đầu điều này bằng cách thêm ActionCable trong routes.

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

Điều này sẽ đặt một điểm cuối WebSocket trên http://localhost:3000/cable có thể kết nối với Javascript như sau.

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

Vì vậy, Rails biết rằng các MessagesChannel map đến thông điệp như thế nào? Không. Cần phải chỉ rõ điều này.

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

Trong các ví dụ phức tạp hơn, bạn có thể tự động tạo tên kênh dựa trên người dùng được xác thực, các thông số bổ sung và nhiều hơn nữa. Trong ví dụ, đơn giản và chỉ cần mã hóa cứng một thuê bao cho luồng tin nhắn.

Cuối cùng, chúng ta cần cập nhật JS để chèn HTML nhận được qua cable vào giao diện người dùng.

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

Mã này thực hiện như sau. Trước tiên, nó tìm các phần tử .thread và .num trong DOM. , nếu chúng ta đang xem tin nhắn (trong view/messages/show.html.erb) thì hiển thị tin nhắn cho 1 số điện thoại. Nếu chúng ta đang ở chế độ xem chỉ mục (views/messages/index.html.erb), hiển thị thông báo mới nhất từ tất cả các số, chúng ta sẽ thay thế các tin nhắn hiện có bằng HTML mới.

Để thực hiện tất cả công việc này, chúng ta cần phải thêm một thuộc tính number vào phần tử .thread và mỗi phần tử .message để chúng ta biết được số nào liên quan.

<!-- 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 %>

Trả lời tin nhắn

Bây giờ, đã nhận được tin nhắn, việc tiếp theo là trả lời tin nhắn Để gửi một tin nhắn SMS qua Nexmo, chúng ta sẽ phải thêm gem nexmo vào app.

# Gemfile
gem 'nexmo'

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

Như bạn thấy, chúng tôi cũng đã thêm vào gem dotenv. Điều này chỉ nhằm làm cho mọi thứ trở nên dễ dàng hơn vì nó sẽ cho phép ứng dụng tải chứng chỉ API của chúng tôi từ tệp .env. Các nexmo gem tự động lấy các biến môi trường và sử dụng chúng để khởi tạo các khách hàng. Bạn có thể tìm thấy các thông tin xác thực của mình trên trang cài đặt tài khoản Nexmo .

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

Chúng tôi cũng đã thêm NEXMO_NUMBER vào tệp .env ở đây.

Tiếp theo, chúng ta hãy chuyển biểu mẫu thư mới thành dạng từ xa và sử dụng ActionCable để hiển thị các bản gửi mới của khách hàng thay vì chuyển hướng trang.

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

Trong controller,

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

Send_cable là tạo Action Cable từ trước, và send_sms sẽ được thực hiện tiếp theo.

Trước khi tiếp tục, thực hiện xóa văn bản khi gửi.

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

Cuối cùng, hãy gửi SMS đến đúng số.

# 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

Đó là nó, bây giờ bạn sẽ có đầy đủ các tin nhắn SMS 2 chiều để Rails nhắn tin tại chỗ với sự giúp đỡ của Action Cable Nexmo và Rails 5. Khởi động lại máy chủ của bạn nếu cần và gửi một số thông báo để xem tất cả hành động.

Nguồn: https://www.nexmo.com/blog/2016/07/14/building-customer-service-chat-rails-5-action-cable-sms-dr/


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí