Phone verification using SMS via Twilio

In this blog post, I’m going to show you how to do phone verification using SMS via Twilio. We will be using Twilio gem.

Requirement

  • When a user signs up , we want to send an SMS to that user with a random string to verify user’s phone number.
  • If that user replies back with that code, then verify user’s phone number in the app. Once the phone number is verified, then we can use that phone number for future use.

Step 1: Create required columns in users table

Let’s create phone_number, phone_verification_code and phone_verified columns in the users table.

 $ bin/rails generate migration AddPhoneAttributesToUsers phone_number:string phone_verification_code:string phone_verified:boolean

Then run the migration.

Step 2: Add phone number field in registration form

Add phone_number field in the registration form.

  <%= f.text_field :phone_number %>

Step 3: Send an SMS with verification code

When a user submits registration form, we need to send SMS if phone number is present. To handle this, add following code in User model.

class User < ActiveRecord::Base
  scope :unverified_phones,  -> { where(phone_verified: false) }

  before_save :set_phone_attributes, if: :phone_verification_needed?
  after_save :send_sms_for_phone_verification, if: :phone_verification_needed?

  def mark_phone_as_verified!
    update!(phone_verified: true, phone_verification_code: nil)
  end

  private

  def set_phone_attributes
    self.phone_verified = false
    self.phone_verification_code = generate_phone_verification_code

    # removes all white spaces, hyphens, and parenthesis
    self.phone_number.gsub!(/[\s\-\(\)]+/, '')
  end

  def send_sms_for_phone_verification
    PhoneVerificationService.new(user_id: id).process
  end

  def generate_phone_verification_code
    begin
     verification_code = SecureRandom.hex(3)
    end while self.class.exists?(phone_verification_code: verification_code)

    verification_code
  end

  def phone_verification_needed?
    phone_number.present? && phone_number_changed?
  end
end

We have added 2 major changes in the user model,

  • set_phone_attributes method is set in before_save callback.
  • send_sms_for_phone_verification method is set in after_save callback.

In set_phone_attributes method, we are setting up the phone attributes mainly sanitizing phone number and generating unique phone verification code. In send_sms_for_phone_verification method, we send SMS to the user. Creation of SMS for the phone verification message is handled in PhoneVerificationService class.

class PhoneVerificationService
  attr_reader :user

  def initialize(options)
    @user = User.find(options[:user_id])
  end

  def process
    send_sms
  end

  private

  def from
    # Add your twilio phone number (programmable phone number)
    Settings.twilio_number_for_app
  end

  def to
    # +1 is a country code for USA
    "+1#{user.phone_number}"
  end

  def body
    "Please reply with this code '#{user.phone_verification_code}' to
    verify your phone number"
  end

  def twilio_client
    # Pass your twilio account sid and auth token
    @twilio ||= Twilio::REST::Client.new(Settings.twilio_account_sid,
                                         Settings.twilio_auth_token)
  end

  def send_sms
    Rails.logger.info "SMS: From: #{from} To: #{to} Body: \"#{body}\""

    twilio_client.account.messages.create(
      from: from,
      to: to,
      body: body
    )
  end
end

In PhoneVerificationService class, we have defined user as an attribute reader and in initialize method, we have set the user object to it. Now if you see process method, it does lots of stuff for us.

Lets go through each method.

  • from - In this method, we set up the twilio phone number e.g. programmable number.
  • to - In this method, we set the phone number to which we want to send an SMS.
  • body - In this method, we build text message with verification code.
  • twilio_client - It creates twilio client based on twilio account sid and auth token.
  • send_sms - And last, it sends SMS to the user.

Step 4: Set request URL for phone verification in Twilio

As of now the system has the capability to send SMS to a user. Now we need to add capability to receive the SMS and to match the verification code.

First, we need to set up a request URL in Twilio account.

Open twilio account and under NUMBERS section/tab, click on your Twilio number. Then in Messaging section, add request URL with HTTP POST method. Add URL like this.

http://your.ngrok.com/phone_verifications/verify_from_message/

But to make it work, we need our Rails app on the public internet. There are two options for this:

  1. Deploy Rails app to your VPS or PaaS of choice.
  2. Use a tunneling service to take the server running on your development machine and make it available at an address on the public internet.

I’m going to use Ngrok tunneling service for the purpose of this blog. You can check this blog for more about its usage.

Step 5: Create phone verification controller

We need one more controller, which will handle phone verification when request comes from Twilio. When a user replies back with a verification code, it will trigger request URL through Twilio API. To handle that request, let’s add phone verifications controller.

  $ bin/rails generate controller phone_verifications

Add new route in config/routes.rb

post "phone_verifications/verify_from_message" => "phone_verifications#verify_from_message"

Add following code to the PhoneVerificationsController.

class PhoneVerificationsController < ApplicationController
  skip_before_action :verify_authenticity_token

  def verify_from_message
    user = get_user_for_phone_verification
    user.mark_phone_as_verified! if user

    render nothing: true
  end

  private

  def get_user_for_phone_verification
    phone_verification_code = params['Body'].try(:strip)
    phone_number            = params['From'].gsub('+1', '')

    condition = { phone_verification_code: phone_verification_code,
                  phone_number: phone_number }

    User.unverified_phones.where(condition).first
  end
end

In this controller, we added skip_before_action :verify_authenticity_token, this is because we need to allow twilio request in our Rails app which is actually an outside request (e.g. not secured request). This means we have disabled CSRF detection for this controller.

Now look at the verify_from_message method, in this method we take phone verification code and phone number from params hash. Using those data, we find the user from the database. Once we get the user, then we mark user’s phone number as a verified phone number.

Finally we are set to send business level text messages to the verified phone number.

This blog has more infomation about how to make secure twilio requests.

Author information in jekyll blog

BigBinary’s blog is powered by jekyll. In every blog we display author’s name, author’s twitter handle, author’s github id and author’s avatar. In this blog I’m going to discuss how we collect all that information in a simple manner.

We create a directory called _data in the root folder. This directory has a single file called authors.yml which in our case looks like this.

vipulnsward:
  name: Vipul
  avatar: http://bigbinary.com/assets/team/vipul.jpg
  github: vipulnsward
  twitter: vipulnsward
neerajdotname:
  name: Neeraj Singh
  avatar: http://bigbinary.com/assets/team/neeraj.jpg
  github: neerajdotname
  twitter: neerajdotname

We do not need to do anything to load authors.yml . It is automatically loaded by jekyll.

When we create a blog then the top of the blog looks like this.

---
layout: post
title: How to deploy jekyll site to heroku
categories: [Ruby]
author_github: neerajdotname
---

Notice the last line where we have put in the author’s github id. That’s the identifier we use to pull in author’s information.

In order to display author’s name we have following code in the layout.


<span class="author-name">
  {{ site.data.authors.[page.author_github].name }}
</span>

Similary to display author’s twitter handle and github id we have following code.


<a href="www.twitter.com/{{site.data.authors.[page.author_github].twitter}}">
  <i class="ico-twitter"></i>
</a>
<a href="www.github.com/{{site.data.authors.[page.author_github].github}}">
  <i class="ico-github"></i>
</a>

Now the blog will display the author information and all this information is nicely centralized in one single file.

2014 - Year in Community Engagement

At BigBinary our team loves to engage with the community as well as help out in different ways. We love contributing to OpenSource, speak and attend different conferences, and help out in community meetups, organizing conferences, and events like RailsGirls .

Short summary

In year 2014 we presented at following 8 conferences across 6 countries.

  • RubyConf Goa, India
  • RubyConf Philippines
  • RedDotRubyConf Singapore
  • DeccanRubyConf Pune, India
  • Madion+Ruby Wisconsin, USA
  • RubyConf Brazil
  • RubyKaigi Tokyo, Japan
  • Golden Gate Ruby Conference San Francisco, USA

Rails and Ruby Conferences

At the start of our travel, we visited RubyConfIndia 2014. The conference took place at an amazing beach resort in Goa. The two days of conference were full of fun and interactions with the best ruby people around India. During the conference our team announced launch of Ruby India to help spread ideas and experiments from the Ruby Indian Community, as well as highlight content from people.

Soon after, I visited Philippines, to conduct a workshop on “Contributing to Rails” at RubyConf Philippines. It was amazing to meet the growing Philippines community. I was happy to spend time with some amazing Rubyists, like Nick Sutterer, Zachary Scott, Konstantin Hasse, Koichi Sasada San, PJ Hagerty, Andre Arko and so on.

After that I and Prathamesh went to Singapore to speak at RedDotRubyConf. We spoke on Arel and ActiveRecord. “RedDorRubyConf” was our first joint talk together at a conference. Again we met a lot of awesome people like Piotr Solnica, Grzegorz Witek, Yinquan Teo, Sayanee Basu, Chinmay Pendharkar and Winston Teo Yong Wei. We also visited Marina Sand Bay and Sentosa Island.

Back in Pune, we hosted the first ever DeccanRubyConf. Our team was busy working on tasks right from building the website, inviting speakers, planning, and other arrangements. The conference had good talks and some really useful workshops. it was a fun one day conference, with attendance of over 170+ people.

The conference also saw our team announce the launch of RubyIndia Podcast, which does regular podcast interviews with notable people from the Ruby Community and Indian Community.

Prathamesh and I, then left on around a one and a half month travel, to attend and speak at multiple conferences.

We started with Madison+Ruby, in Madison, WI. After several missed flights, and a storm, we visited our first US conference after a travel of 48 hours. MadisonRuby was a conference like no other. Several topics touched the humane side of Ruby and the community. We spoke on ‘Building an own ORM using ARel’. Set in the cultural town of Madison, we immensely enjoyed the cheese-curds, farmers markets and game night arranged by the Conf team. A huge thanks to Jim and Jennifer Remsik, for hosting such an amazing event. Thanks also to Scott Ruttencutter for giving us space to work from his office and giving us a tour of the state capital.

We then visited Sao Paulo, Brazil for RubyConf Brazil and presented a talk on Building an ORM using ARel. It was a pleasure to meet Fabio Akita and the CodeMiner team. We made friends with Celso Fernandes and Paulo who were kind enough to help us around, since in Brazil primarily portuguese is spoken. We also met Rafael Franca and Carlos Antonio da Silva who have helped us a lot with Rails issue tracker.

Next Prathamesh headed to RubyKaigi, being held in Tokyo, Japan. He presented on Fixtures in Rails. He met Matz, creator of Ruby on his first day in Japan. Mostly all the core Ruby contributors attended RubyKaigi. He got to interact with Koichi Sasada San, Jonan Scheffler, Akira Matsuda, Godfrey Chan, Richard Schneeman and lot of awesome Rubyists. He also met with his JRuby Core Tom Enebo for the first time. Thanks to Yasuo Honda, Michael Reinsch for helping with Japanese food.

From Brazil, I first visited Miami, and was happy to visit The Lab Miami, WynCode and interact with Rubyists from Miami.

Before heading to San Francisco, for GoGaRuco, I was able to make a quick stop in Boston and visit AlterConf Boston. The theme of the conference was around diversity in tech and gaming industry.

My latest conference was in the amazing city on San Francisco. I presented about ‘Building an ORM’, at GoGaRuCo, which incidentally was the last ever GoGaRuCo. The conference taking place in San Francisco, saw an amazing turnout of crowd. I was able to interact with Sarah Allen, Yehuda Katz, Pat Allen, Sarah Mei, Ryan Davis. I spent most of the time along with Nathan Long, Randy Coulman, and Nathan’s friend Michael Gundlach, who is the creator of popular plugin Adblock. I also ran into Chris Eppstein, creator of compass. All around it was one of the most amazing interactions I had in a conference.

2014, was an amazing year for our team. Together we presented or were part of 8 conferences, launched RubyIndia Newsletter as well as the RubyIndia Podcast, started with 6 new video series on topics from ReactJS to Rubymotion to Selenium, published numerous blogs, and contributed to a number of OpenSource projects.

2015, starts with our team presenting at GardenCityRuby Conf. We hope to get more such chances to interact and help out the community. Onwards to a new year!

Migrating existing session cookies while upgrading to Rails 4.1 and above

Rails 4.1 introduced JSON serialization for cookies. Earlier all the cookies were serialized using Marshal library of Ruby. The marshalling of cookies can be unsafe because of the possibility of remote code execution vulnerability. So the change to :json is welcoming.

The new applications created with Rails 4.1 or 4.2 have :json as the default cookies serializer.

rake rails:update used for upgrading existing Rails apps to new versions rightly changes the serializer to :json.

Rails.application.config.action_dispatch.cookies_serializer = :json

Deserialization error

However that change can introduce an issue in the application.

Consider a scenario where the cookies are being used for session storage. Like many normal Rails apps, the current_user_id is being stored into the session.

session[:user_id] = current_user_id

Before Rails 4.1 the cookie will be handled by Marshal serializer.

cookie = Marshal.dump(current_user_id) # 42 => "\x04\bi/"
Marshal.load(cookie) # "\x04\bi/" => "42"

After the upgrade the application will try to unserialize cookies using JSON which were serialized using Marshal.

JSON.parse cookie # Earlier dumped using Marshal
# JSON::ParserError: 757: unexpected token at i/'

So the deserialization of the existing cookies will fail and users will start getting errors.

Hybrid comes to rescue

To prevent this Rails provides with a hybrid serializer. The hybrid serializer deserializes marshalled cookies and stores them in JSON format for the next use. All the new cookies will be serialized in the JSON format. This gives happy path for migrating existing marshaled cookies to new Rails versions like 4.1 and 4.2.

To use this hybrid serializer, set cookies_serializer config as :hybrid as follows:

Rails.application.config.action_dispatch.cookies_serializer = :hybrid

After this, all the existing marshalled cookies will be migrated to :json format properly and in the future upgrade of Rails, you can safely change the config from :hybrid to :json which is the default and safe value of this config.

Rails Girls Pune 2014

The second edition of RailsGirls Pune event was an amazing day spent with some equally amazing folks. The event took place on 13th of December and it saw a huge turnout of around 150+ women from various colleges and companies. It was a free event for beginners interested in learning about coding and building applications using Ruby on Rails.

BigBinary was happy to be one of the sponsors of the event.

The event was organized by Rajashree Malvade, Shifa Khan, Pooja Salpekar, Dominika Stempniewicz, and Magdalena Sitarek.

BigBinary team reached the venue, ThoughtWorks office, Pune, at about 8.30 AM. Rajashree did the introductions and Gautam Rege, and I did the kick off. Gautam introduced Ruby, along with how magical Ruby is and the importance of the event. I spent some time explaining how RailsGirls began, as well as Rails Bridge and other similar events.

RailsGirls pune kick-off

Next all instructors were grouped together. Grouping was done in such a way that advanced instructors were paired with intermediate and beginner instructors.

The talented folks from ThoughtWorks had created a fun movie explaining the three different tracks - beginner, intermediate and advanced into which the students were divided.

I, Prathamesh and Richa Trivedi took to one of the advanced track groups. We started off by pairing people to work with their partner and did a health check of everyones' system. Many of the participants in our group had 1-2 years of professional experience in Java, .Net and so forth. This meant they were quite familiar with setting up various things on their machine and that was a great help. We started with basics of ruby- variables, loops, blocks, each, methods, classes, etc. This took about 2 hours and then we started with Rails and MVC.

Santosh paired with Dinesh and participated in intermediate track of a group of four students. They started with basics of Ruby and later started to build simple blog app using Rails and deployed apps to Heroku by the end of the day.

At about 11.30, Siddhant Chothe from TechVision, did an inspiring talk about Web Accessibility, Wiable gem, and his journey in Ruby & Rails world.

Siddhant's session

Then We did the Bentobox activity. Participants were handed a page listing various aspects of software development like infrastructure, frontend, application, storage in boxes. We read out technologies like XML, JSON, AJAX, MongoDB, etc, and asked everyone to write these on stickies and place them in appropriate boxes on the “Bentobox”. This was helpful for the participants to understand what different technologies are related to web-development and where they are used.

Then everyone broke out for lunch. Our enthusiastic lot stayed back to avoid the rush, and began with Rails development. We started by explaining basic MVC concepts and how Rails helps as a framework. We started with a simple App, and created “pages/home” static home page. This helped our group to understand rails generators, routes, controllers and views. With our first page up and running, we went for lunch.

After lunch, a session on Origami was conducted by Nima Mankar. It was a good stress buster after all of the first session’s bombardment over the participants.

Origami Session

Our next objective was to build an app and deploy it to heroku. Our group started out to build “The Cat App”! We began with explaining controllers, CRUD operations, parts of URL, REST, etc. We created a Cat model, and everyone loved the beauty and simplicity of migrations and performing create, update, delete, find using ActiveRecord. We quickly moved on to building CatsController and CRUD operations on the same. We made sure we did not use scaffold, so as to explain the underlying magic, instead of scaffold hiding it away.

Richa with our Group Other part of our Group

Soon everyone had a functional App, and it was fun to introduce GorbyPuff as the star of our App, whose images were displayed as cat records, which store name of the image and url to an image.

We then setup the Apps on heroku and were ready for the next part- Showcase. It was amazing to see so many groups complete the Apps and come up with fun, interesting and quirky ideas. One student created Boyfriend Expense (Kharcha) Management App.

App Showcase

The day ended on a high note amid high enthusiasm from all the participants. We finished the workshop with a huge cake for everyone.

Overall, it was well-organized, fun, enthusiastic and a day well spent.

Thanks to Rajshree, Shifa, Pooja, Dominika and Magdalena for organizing such an awesome event. Both Pune edition events, have shown great interest, and it has left us all looking forward for the next one!

DRYing up Rails Views with View Carriers and Services

Anyone who has done any Rails development knows that views gets complicated very fast. Lately we’ve been experimenting with Carriers ( also called view services ) to clean up views.

There are many already existent solutions to this problem like Draper Gem , or Cells from Trailblazer architecture.

We wanted to start with simplest solution by making use of simple ruby objects that takes care of business logic away from views.

A complex view

Consider this user model

class User
  def super_admin?
    self.role == 'super_admin'
  end

  def manager?
    self.role == 'manager'
  end
end

Here we have a view that display appropriate profile link and changes css class based on the role of the user.

<% if @user.super_admin? %>
  <%= link_to 'All Profiles', profiles_path %>
<% elsif @user.manager? %>
  <%= link_to 'Manager Profile', manager_profile_path %>
<% end %>

<h3 class="<%= if @user.manager? 
                  'hidden' 
               elsif @user.super_admin? 
                  'active' 
               end %>"> 

   Hello, <%= @user.name %>
</h3>

Extracting logic to Rails helper

In the above case we can extract the logic from the view to a helper.

After the extraction the code might look like this

# app/helpers/users_helper.rb

module UsersHelper
  
  def class_for_user user
    if @user.manager?  
      'hidden' 
    elsif @user.super_admin? 
      'active' 
    end
  end

end

Now the view is much simpler.

<h3 class="<%= class_for_user(@user) %>">
   Hello, <%= @user.name %>
</h3>

Why not to use Rails helpers?

Above solution worked. However in a large rails application it will start creating problems.

UsersHelper is a module and it is mixed into ApplicationHelper. So if the Rails project has large number of helpers then all of them are mixed into the ApplicationHelper and sometimes there is a name collision. For example let’s say that there is another helper called ShowingHelper and this helper also has method class_for_user. Now ApplicationHelper is mixing in both modules UsersHelper and ShowingHelper. One of those methods will be overridden and we would not even know about it.

Another issue is that all the helpers are modules not classes. Because they are not classes it becomes difficult to refactor helpers later. If a module has 5 methods and if we refactor two of the methods into two separate methods then we end up with seven methods. Now out of those seven methods in the helper only five of them should be public and the rest two should be private. However since all the helpers are modules it is very hard to see which of them are public and which of them are private.

And lastly writing tests for helpers is possible but testing a module directly feel weird since most of the time we test a class.

Carriers

Lets take a look at how we can extract the view logic using carriers.

class UserCarrier
  attr_reader :user
  
  def initialize user
    @user = user
  end
 
  def user_message_style_class
    if user.manager? 
      'hidden' 
    elsif user.super_admin? 
      'active' 
    end
  end 
end

In our controller

class UserController < ApplicationController
    def show
      @user = User.find(params[:id])
      @user_carrier = UserCarrier.new @user
    end
  end

Now the view looks like this

<% if @user.super_admin? %>
  <%= link_to 'All Profiles', profiles_path %>
<% elsif @user.manager?%>
  <%= link_to 'Manager Profile', manager_profile_path %>
<% end %>

<h3 class="<%= @user_carrier.user_message_style_class %>"> 
  Hello, <%= @user.name %>
</h3>

No html markup in the carriers

Even though carriers are used for presentation we stay away from having any html markup in our carriers. That is because once we open the door to having html markups in our carriers then carriers quickly get complicated and it becomes harder to test them.

No link_to in the carriers

Since carriers are plain ruby objects, there is no link_to and other helper methods. And we keep carriers that way. We do not do include ActionView::Helpers::UrlHelper because the job of the carrier is to present the data that can be used in link_to and complement the usage of link_to.

We believe that link_to belongs to the ERB file. However if we really need to have an abstraction over it then we can create a regular Rails helper method. We minimize usage of Rails helper, we do not avoid it altogether.

Overcoming Double Dots

Many times in our view we end up doing

Email Preference for Tuesday: <%= @user.email_preferences.tuesday_preference %>

This is a violation of Law of Demeter . We call it “don’t use Double Dots”. Meaning don’t do @article.publisher.full_name.

Its just a matter of time before views code looks like this

<%= @article.publisher.active.not_overdue.try(:full_name) %>

Since carriers encapsulate objects into classes, we can overcome this “double dots” issue by delegating behavior to appropriate object.

class UserCarrier
  attr_reader :user :email_preferences
  
  delegate :tuesday_preference, to: :email_preferences
  
  def initialize user
    @user = user
    @email_preferences = user.email_preferences
  end
    
end

After that refactoring we end up with cleaner views like.

Email Preference for Tuesday: <%= @user_carrier.tuesday_preference %>

Note that “Double dot” is allowed at other parts of the code. We do not allow it in views.

Testing

Since the carriers are simple ruby objects it’s easy to test them.

require 'test_helper'

class UserCarrierTest < ActiveSupport::TestCase
  fixture :users
  
  def setup
    manager = users(:manager)
    @user_carrier = UserCarrier.new manager 
  end

  def test_css_class_returned_for_manager
    assert_equal 'hidden', @user_carrier.user_message_style_class
  end
  
end

Summary

Carriers allow us to encapsulate complex business logic in simple ruby objects.

This helps us achieve clearer separation of concern, clean up our views and avoid skewed and complex views. Our views are free of “double dots” and we end up with simple tests which are easy to maintain.

We decided to call it a “carrier” and not “presenter” because the word “presenter” is overloaded and has many meanings.

Make Outbound Calls From the Browser to Phone using Twilio and Rails

In this blog post we will see how to make outbound phone calls from the browser to a phone using Twilio . We will make use of the Twilio-JS library and Twilio-Ruby gem.

The Rails App we will be creating, is based on the Twilio Client Quick-start tutorial. That Twilio tutorial makes use of Sinatra. We will see how we can achieve this in a Rails application.

Step 1. Setup Twilio Credentials and TwiML App

We need to setup twilio credentials. We can find account ID and auth token from our account information.

When the call is made using browser then the phone that is receiving the call has to see a number from which the call is coming. So now we need to setup a Twilio verified number. This number will be used to place the outgoing calls from. How to setup a verified number can be found here.

When our app make a call from the browser using twilio-js client, Twilio first creates a new call connection from our Browser to Twilio. It then sends a request back to our server to get information about what to do next. We can respond by asking twilio to call a number, say something to the person after a call is connected, record a call etc.

Sending of this instructions is controlled by setting up a TwiML application. This application provides information about the end point on our server, where twilio should send the request to fetch instructions. TwiML is a set of instructions, that we can use to tell Twilio what to do in different cases like when an outbound phone call is made or when an inbound SMS message is received.

Given below is an example that will say a short message How are you today? in a call.

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Say voice="woman">How are you today?</Say>
</Response>

The TwiML app can be created here. Once the app is configured then we will get appsid.

We need to configure following information in our Rails Application:

twilio:
  verified_number: <%= ENV['TWILIO_VERIFIED_NUMBER']%>
  account_sid: <%= ENV['TWILIO_ACCOUNT_SID'] %>
  auth_token: <%= ENV['TWILIO_AUTH_TOKEN'] %>
  call_app_sid: <%= ENV['TWILIO_CALL_APP_SID'] %>

Step 2. Generate capability token to be used by twilio-js

After we have the config setup, we will proceed to create the capability token. This token will be generated using the ruby gem, and passed to the javascript SDK. The token helps the twilio-js client determine, what permissions the application has like making calls, accepting calls, sending SMS, etc.

We define a TwilioTokenGeneratorService for this purpose.

class TwilioTokenGeneratorService

  def process
    capability = twilio_capability()
    capability.generate
  end

  private

  def twilio_capability
    capability ||= Twilio::Util::Capability.new Settings.twilio.account_sid, Settings.twilio.auth_token
    capability.allow_client_outgoing Settings.twilio.call_app_sid
    capability
  end

end

As you can see, we first define a new Twilio::Util::Capability instance and pass credentials to it. We then call allow_client_outgoing method and pass the client Sid to it. This is the identifier for the TwiML application we have previously created on Twilio. Calling allow_client_outgoing gives permission to the client to make outbound calls from Twilio. Finally we call the generate method to create a token from the capability object.

Step 3. Define view elements and pass token to it

The generated token will now be passed to the Twilio JS client for connecting with Twilio. In our App we define CallsController, and index action in this controller. This action takes care of setting the capability token. Our index view consists of two buttons- to place and hangup a call, a number input field, call logs, and data field to pass capability token to the javascript bindings. We import the Twilio-JS library in the view. The css styling being used is from the Twilio example.

<div id="twilioToken" data-token="<%= @twilio_token %>"></div>

<button id="caller" class="call">Call</button>
<button id="hangup" class="hangup">Hangup</button>

<input type="text" id="phoneNumber" placeholder="Enter a phone number to call"/>

<div id="log">Loading pigeons...</div>

<script type="text/javascript" src="//static.twilio.com/libs/twiliojs/1.2/twilio.min.js"></script>

Step 4. Define coffeescript bindings to handle TwilioDevice connection to Twilio

Next we setup coffeescript bindings to handle initialization of TwilioDevice and making use of entered number to place calls Twilio. We are taking care of various events like connect, disconnect, ready, etc. on TwilioDevice instance. More information about TwilioDevice usage can be found here.

class TwilioDevice
  constructor: ->
    @initTwilioDeviceBindings()
    @initFormBindings()

  initTwilioDeviceBindings: ->
    twilio_token = $('#twilioToken').data('token')
    twilio_device = Twilio.Device

    # Create the Client with a Capability Token
    twilio_device.setup(twilio_token, {debug: true});

    #/* Let us know when the client is ready. */
    twilio_device.ready ->
      $("#log").text("Ready")

    #/* Report any errors on the screen */
    twilio_device.error (error) ->
      $("#log").text("Error: " + error.message)

    #/* Log a message when a call connects. */
    twilio_device.connect (conn) ->
      $("#log").text("Successfully established call")

    #/* Log a message when a call disconnects. */
    twilio_device.disconnect (conn) ->
      $("#log").text("Call ended")

  initFormBindings: ->
    $('#caller').bind "click", (event) ->
      params = {"phone_number": $('#phoneNumber').val()}
      Twilio.Device.connect(params)

    $('#hangup').bind "click", (event) ->
      Twilio.Device.disconnectAll()

$ ->
  new TwilioDevice()

If we now load this page, we should be able to see our app saying its ready to take calls.

Twilio Rails App Ready

Step 5. Define TwiML Response Generator Service

The final step before we place calls from our App is to handle callbacks from Twilio and return TwiML response. For this we are going to define TwilioCallTwiMLGeneratorService which takes care of generating this response. More information about how we need to define the response and individual fields can be found from Twilio’s docs.

What we need to define is a response as below:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial callerId="+15005550000">
    <Number>+15005550001</Number>
  </Dial>
</Response>

We are making use of two elements here - Dial, which makes Twilio place a call using defined callerId value, as the number from which the call is made, which is displayed on the callee’s phone. Note that this is the same verified number that we had specified before. Then we specify Number which is the number, to which we want to place the call to. This number is passed first by the javascript client to Twilio, and then back to our application by Twilio, which we use to generate the response as above.

We define our TwilioCallTwiMLGeneratorService to take in a phone number as parameter. It creates an instance of Twilio::TwiML::Response and tapping on this instance we provide Dial element with a :callerId value, and the Number to place the call to. We validate the number before passing it back, and return an error if the number is invalid.

class TwilioCallTwiMLGeneratorService
  attr_reader :phone_number
  VALID_PHONE_NUMBER_REGEX = /^[\d\+\-\(\) ]+$/ # Matches valid phone numbers acceptable to Twilio

  def initialize phone_number
    @phone_number = phone_number
  end

  def process
    Twilio::TwiML::Response.new do |r|
      if VALID_PHONE_NUMBER_REGEX.match(phone_number)
        r.Dial :callerId => Settings.twilio.verified_number do |d| # callerId is number from which call is made.
          d.Number(CGI::escapeHTML phone_number) # The number to call
        end
      else
        r.Error("Invalid number!")
      end
    end.text.strip
  end

end

Step 6. Send TwiML response on Twilio callback

We are now set to define twilio’s callback handler. This will be handled by the create_call action in CallsController. Twilio will be sending this endpoint a POST request along with some information specified here. We make use of phone_number being passed to us by Twilio and pass it along to the TwilioCallTwiMLGeneratorService, which return us with valid TwiML response. Since TwiML is a flavour of XML, we make using render xml to return the response.

def create_call
  response_to_twilio_callback = TwilioCallTwiMLGeneratorService.new(call_params[:phone_number]).process
  render xml: response_to_twilio_callback
end

def call_params
  params.permit(:phone_number)
end

As create_call endpoint will be used by Twilio API, we need to skip authenticity token check for this action.

class CallsController < ApplicationController
  skip_before_action :verify_authenticity_token, only: [:create_call]
end

Finally we need to specify the callback url in our TwiML App on Twilio. For testing this locally, we can make use of a service like https://ngrok.com/, to expose this endpoint.

Twilio TwiML App setting

Our service is now ready to place calls. The complete Rails application code that we have created can be found here.

Happy calling everyone!