Статьи

Добавление возможностей SMS в приложение Rails

В недавнем проекте одним из технических требований была интеграция службы SMS с приложением Rails, чтобы пользователи могли проверять свои учетные записи с помощью своего мобильного устройства, а также разрешать приложению отправлять SMS-сообщения таким пользователям.

Оказывается, добавить такие возможности чрезвычайно легко, особенно при использовании такого сервиса, как Twilio . На мой взгляд, это одна из лучших услуг на рынке сегодня, и ее простота не имеет себе равных.

Эта статья проведет вас через шаги, необходимые для отправки и получения текстовых сообщений через приложение Rails. Более конкретно, он будет охватывать:

  • Записаться на Twilio
    • Использование песочницы Twilio
    • Проверка номера телефона с помощью Twilio
  • Отправка и получение SMS-сообщений через приложение Rails
    • Создание базового приложения
    • Соединяя основные части вместе
    • Интеграция приложения с Twilio
    • Выставление вашего локального хоста в Интернет
  • Написание юнит-тестов и имитация внешних звонков

В конце у нас должно быть работающее приложение, которое может отправлять и получать текстовые сообщения. Наслаждайтесь!

Записаться на Twilio

Процесс регистрации в Twilio действительно прост: вам просто нужно указать свое имя, адрес электронной почты и пароль. Как только вы закончите, вы будете перенаправлены на их панель управления.

Использование песочницы Twilio

Теперь, когда мы зарегистрировались, давайте посмотрим, что произойдет, когда мы отправим простое «привет» текстовое сообщение на номер телефона Twilio. Мы получаем следующее сообщение об ошибке:

Хорошо, нам нужно включить PIN-код с панели инструментов, давайте продолжим и сделаем это. После того, как сообщение успешно отправлено в формате PIN ‘hello’ , мы получаем следующий автоматический ответ:

Большой! Мы успешно взаимодействовали с Песочницей Twilio.

Проверка номера телефона с помощью Twilio

Находясь в режиме песочницы, вам нужно добавить и проверить номера телефонов, которые вы хотите включить для получения текстовых сообщений программно. Это обязательный шаг, и вы не получите никаких сообщений из приложения Rails, если не завершите этот процесс.

После того, как вы добавите номер телефона и нажмете кнопку «Позвонить по этому номеру», система автоматически сделает телефонный звонок на указанный номер. Вам необходимо ответить на звонок и ввести код, который отображается на экране. После этого вам должно быть хорошо идти.

Отправка и получение SMS-сообщений через приложение Rails

Основное применение

В этом разделе я собираюсь начать с нового приложения Rails на основе Ruby 1.9.3 и Rails 3.2.5 в среде Mac OSX. Вы можете использовать существующее приложение, если оно у вас уже есть.

Во-первых, давайте создадим новое приложение rails. Я пропускаю звездочки и javascript просто для простоты (и потому что нам не нужно для нашего примера приложения):

rails new sms_app —skip-sprockets —skip-javascript

view raw
new_sms_app
hosted with ❤ by GitHub

Затем мы создаем ресурс User, который будет использоваться в качестве точки входа для создания новых пользователей и отправляем им начальное текстовое сообщение для подтверждения учетной записи:

rails g resource user name:string email:string phone:string verified:boolean —skip-assets

view raw
user_resource
hosted with ❤ by GitHub

Теперь перенесите базу данных и добавьте следующие проверки в модель User:

class User < ActiveRecord::Base
attr_accessible :email, :name, :phone
validates :name, presence: true
validates :email, :phone, presence: true, uniqueness: true
end

view raw
user.rb
hosted with ❤ by GitHub

Для последнего шага нам нужно создать контроллер, который будет использоваться для проверки учетной записи пользователя. Вот где наше приложение будет получать обратные вызовы от Twilio:

rails g controller verifications —skip-assets

view raw
gistfile1.sh
hosted with ❤ by GitHub

Основная структура готова. Следующим шагом будет соединить части вместе.

Соединяя основные части вместе

Теперь, когда наша структура скелета готова, давайте начнем собирать части. Первое, что мы собираемся сделать, это отредактировать config / rout.rb и добавить следующие маршруты:

resources :users
resource :verifications
root to: ‘users#new’

view raw
routes.rb
hosted with ❤ by GitHub

Затем отредактируйте app / controllers / users_controller.rb и добавьте следующие методы:

class UsersController < ApplicationController
def new
@user = User.new
end
def create
@user = User.new(params[:user])
if @user.save
render text: «Thank you! You will receive an SMS shortly with verification instructions.»
else
render :new
end
end
end

Для следующего шага нам нужно создать файл представления для Users # new в app / views / users, чтобы мы могли зарегистрировать пользователей для нашего замечательного сервиса:

<h1>User Registration</h1>
<%= form_for @user do |f| %>
<% if @user.errors.any? %>
<ul>
<% @user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
<p><%= f.label :name %><br>
<%= f.text_field :name%></p>
<p><%= f.label :email %><br>
<%= f.text_field :email%></p>
<p><%= f.label :phone %><br>
<%= f.text_field :phone%></p>
<%= f.submit %>
<% end %>

view raw
new.html.erb
hosted with ❤ by GitHub

Наконец, откройте app / controller / verifications_controller.rb и добавьте метод создания заполнителя:

class VerificationsController < ApplicationController
def create
end
end

Теперь у нас есть основное рабочее приложение. Запустите сервер Rails ( rails ) и направьте ваш браузер по адресу http: // localhost: 3000 . Убедитесь, что вы удалили public / index.html, иначе вы получите индексный файл Rails по умолчанию. Вы должны увидеть что-то вроде этого:

Интеграция нашего приложения с Twilio

Здесь начинается самое интересное. Сначала добавьте следующее в ваш Gemfile и запустите пакетную установку :

gem ‘twilio-ruby’

view raw
gistfile1.rb
hosted with ❤ by GitHub

Далее мы собираемся создать файл конфигурации, который будет содержать информацию, необходимую для использования Twilio API. Создайте файл config / twilio.yml и добавьте следующее:

development:
from: your-from
sid: your-sid
token: your-token

view raw
twilio.yml
hosted with ❤ by GitHub

У вас должна быть вся информация, необходимая для файла конфигурации, если вы правильно зарегистрировались в Twilio. А если нет, то обязательно следуйте инструкциям в начале этой статьи.

Наличие отдельной записи для каждой среды действительно полезно и позволяет вам иметь различные конфигурации для каждой среды. Вы бы не хотели использовать свою производственную учетную запись для разработки и свою учетную запись для производства, не так ли?

Для следующего шага нам нужно загрузить эту конфигурацию и сделать ее доступной для всего приложения. Есть несколько разных способов сделать это, но в этом примере я собираюсь использовать константу. Создайте файл config / initializers / twilio.rb и добавьте следующее:

path = File.join(Rails.root, «config/twilio.yml»)
TWILIO_CONFIG = YAML.load(File.read(path))[Rails.env] || {‘sid’ => », ‘from’ => », ‘token’ => »}

view raw
twilio.rb
hosted with ❤ by GitHub

Обратите внимание, что по умолчанию мы используем предварительно заполненный Hash, если не можем найти текущую среду. Это необходимо для предотвращения ошибок при доступе к значениям для несуществующей конфигурации.

Ok! Теперь мы готовы отправить нашим пользователям текстовое сообщение с информацией о том, как подтвердить свою учетную запись. Готов?

Измените UsersController # create, включив в него следующее:

class UsersController < ApplicationController
def new
@user = User.new
end
def create
@user = User.new(params[:user])
if @user.save
render text: «Thank you! You will receive an SMS shortly with verification instructions.»
# Instantiate a Twilio client
client = Twilio::REST::Client.new(TWILIO_CONFIG[‘sid’], TWILIO_CONFIG[‘token’])
# Create and send an SMS message
client.account.sms.messages.create(
from: TWILIO_CONFIG[‘from’],
to: @user.phone,
body: «Thanks for signing up. To verify your account, please reply HELLO to this message.»
)
else
render :new
end
end
end

Затем вернитесь в браузер и откройте приложение Rails. После того, как вы зарегистрируетесь по номеру своего мобильного телефона, вы получите текстовое сообщение, подобное этому:

Это довольно круто, не правда ли?

Для следующего шага нам нужно изменить Verification # create, чтобы иметь возможность получать обратные вызовы от Twilio и проверять пользователя, отправляющего нам текстовое сообщение:

class VerificationsController < ApplicationController
before_filter :get_user
def create
@user.update_attribute(:verified, true)
# You could send another message acknowledging the verificaton
head :ok
end
private
def get_user
unless @user = User.find_by_phone(params[‘From’])
head :not_found
end
end
end

Когда Twilio отправляет обратный вызов в наше приложение, оно включает в себя около шестнадцати параметров. Для этого примера мы заботимся только о From . Вот остальные параметры, если вам интересно:

{
«AccountSid»=>«<string>»,
«Body»=>«the message content»,
«ToZip»=>«<string>»,
«FromState»=>«<string>»,
«ToCity»=>«<string>»,
«SmsSid»=>«<string>»,
«ToState»=>«<string>»,
«To»=>«<string>»,
«ToCountry»=>«<string>»,
«FromCountry»=>«<string>»,
«SmsMessageSid»=>«<string>»,
«ApiVersion»=>«<string>»,
«FromCity»=>«<string>»,
«SmsStatus»=>«<string>»,
«From»=>«<string>»,
«FromZip»=>«<string>»
}

view raw
gistfile1.rb
hosted with ❤ by GitHub

Выставление вашего локального хоста в Интернет

Чтобы получать обратные вызовы от Twilio в нашем локальном Rails-приложении, нам нужно выставить наш локальный сервер для внешнего «мира». Для этого есть три простых варианта:

Статический IP-адрес: если у вас уже есть статический IP-адрес у вашего интернет-провайдера, это не составляет труда. Просто настройте маршрутизатор для перенаправления запросов с внешнего порта 3000 на ваш внутренний сервер через порт 3000 и используйте свой внешний IP в качестве URL-адреса SMS в Twilio.

Showoff.io: согласно их веб-сайту , это «самый простой способ поделиться локальным хостом через Интернет». И это довольно просто на самом деле. Просто установите их гем и запустите их двоичный файл с внутренним портом, которым вы хотите поделиться, и он сгенерирует короткий URL, который вы можете использовать извне. Вы можете бесплатно пользоваться услугой в течение пяти минут или приобрести один из платных планов. На момент написания этой статьи планы составляют 1 доллар за однодневный пропуск или 5 долларов без ограничений.
Пример использования:

# Manual install
gem install showoffio
# Or via Bundle
gem ‘showoff-io’, group: :development
bundle install
# Sharing your localhost on port 3000
show 3000

view raw
gistfile1.rb
hosted with ❤ by GitHub

Tunnlr: Подобно Showoff.io , это служба пересылки, которая позволяет вам использовать локальный сервер для внешних пользователей. Их текущий гем tunnlr_connector (1.0.3) работает только с Rails, но его легко расширить для работы с другими фреймворками. На момент написания этой статьи вы можете бесплатно пользоваться этой услугой в течение 30 дней, после чего она стоит 5 долларов в месяц. Одна вещь, которую вы должны сделать, это зарегистрироваться в службе, прежде чем вы сможете использовать драгоценный камень. Он задаст вам вопросы о вашей учетной записи в процессе настройки.

Пример использования:

# Manual install
gem install tunnlr_connector
# Or via Bundle
gem ‘tunnlr_connector’, group: :development
bundle install
# Configure for the first time
rake tunnlr:configure
# Sharing your localhost
rake tunnlr:start

view raw
gistfile1.rb
hosted with ❤ by GitHub

Из трех приведенных выше вариантов я лично использую Tunnlr, и это то, что мы будем использовать в этом примере. Это чрезвычайно полезно при работе в разработке и взаимодействии с песочницей Twilio.

После запуска Tunnlr скопируйте созданный URL-адрес и вставьте его в поле «SMS-URL» на панели инструментов Twilio. Не забудьте добавить / подтверждение в конец URL:

Мы все готовы сейчас. Ответ на сообщение о подтверждении, которое мы получили ранее, обновит наш статус пользователя до подтвержденного.

Не забывайте всегда указывать PIN-код с панели мониторинга Twilio к сообщениям, которые вы отправляете в режиме песочницы, в противном случае Twilio ответит сообщением об ошибке. Давай и попробуй.

Написание юнит-тестов и имитация внешних звонков

Последняя часть — это написание тестов для нашего приложения и насмешка по внешним вызовам API Twilio. Я должен упомянуть, что я собираюсь рассказать только о функциональном тесте для UsersController, чтобы продемонстрировать, как работает mocking . Я оставляю другие тесты в качестве упражнения для читателя.

Во время тестов вы должны избегать вызовов внешних служб и отправки реальных текстовых сообщений. Вот где насмешливые объекты пригодятся. В этой статье я буду использовать RR , потрясающий «тестовый двойной» фреймворк.

В вашем Gemfile добавьте следующее и запустите пакетную установку :

group :test do
gem ‘rr’
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Затем откройте test / test_helper.rb и добавьте следующее, что позволит нам использовать RR для насмешки вызовов API Twilio:

class ActiveSupport::TestCase
include RR::Adapters::TestUnit
end

view raw
test_helper.rb
hosted with ❤ by GitHub

Теперь откройте test / functions / users_controller_test.rb и добавьте следующее:

require ‘test_helper’
class UsersControllerTest < ActionController::TestCase
test «#new» do
get :new
assert_response :success
assert_template :new
end
test «#create succeeds» do
assert_difference ‘User.count’ do
post :create, user: {name: ‘John Doe’, email: [email protected], phone: ‘555-444-3434’}
assert_response :ok
end
end
test «#create fails on validation» do
assert_no_difference ‘User.count’ do
post :create, user: {name: ‘Joe’}
assert_response :ok
assert_template :new
assert !assigns(:user).valid?
end
end
end

Если вы запустите этот тест, он потерпит неудачу. Не потому, что тест написан неправильно, а потому, что REST-клиент Twilio не может выполнить запрос к указанному ресурсу. Это происходит главным образом из-за того, что наш код пытается отправить реальное текстовое сообщение в тестовом режиме.

Пусть начнется насмешка!

Первое, что нам нужно сделать, это создать ложный класс, который содержит метод method_missing, который возвращает экземпляр self . Это позволяет нам смоделировать цепочку методов в коде Twilio client.account.sms.messages.create () :

class MockedTwilioClient
def method_missing(*args)
self
end
end

Следующим шагом является использование метода mock для записи клиентского объекта Twilio и возврата экземпляра нашего класса MockedTwilioClient :

mock(Twilio::REST::Client).new(»,»){ MockedTwilioClient.new }

view raw
gistfile1.rb
hosted with ❤ by GitHub

Наконец, собрав все вместе, наш тест должен выглядеть так:

require ‘test_helper’
class MockedTwilioClient
def method_missing(*args)
self
end
end
class UsersControllerTest < ActionController::TestCase
test «#new» do
get :new
assert_response :success
assert_template :new
end
test «#create succeeds» do
mock(Twilio::REST::Client).new(»,»){ MockedTwilioClient.new }
assert_difference ‘User.count’ do
post :create, user: {name: ‘John Doe’, email: [email protected], phone: ‘555-444-3434’}
assert_response :ok
end
end
test «#create fails on validation» do
assert_no_difference ‘User.count’ do
post :create, user: {name: ‘Joe’}
assert_response :ok
assert_template :new
assert !assigns(:user).valid?
end
end
end

Теперь, когда вы запускаете тесты, он не только проходит, но и проверяет внешние вызовы API Twilio из нашего UsersController .

Вывод

В этой статье показано, как просто добавить возможности SMS в приложение Rails, и у вас должно быть достаточно знаний, чтобы применить полученные знания в своих собственных проектах. В нем также описаны шаги, которые необходимо предпринять, чтобы вывести свой локальный сервер Rails в Интернет; и как можно применять объектный макет, чтобы избежать вызова внешних сервисов во время теста.

Для упрощения примера были сделаны несколько ярлыков, и вы должны использовать их по своему усмотрению. Пример:

  • Лучшие проверки, лучшие тесты
  • В UsersController # create код, отправляющий текстовое сообщение, следует переместить в модель User в действие after_create и, возможно, даже выполнить как фоновое задание или отправить его в очередь для последующей обработки.
  • … вы поняли идею.

Ресурсы

Twilio:

  • Сайт: www.twilio.com
  • Драгоценный камень: twilio-ruby

Showoff.io:

  • Сайт: www.showoff.io
  • Драгоценный камень: showoff-io

Tunnlr:

RR: