When you need to get a bunch of remote people to talk together, a conference call is the simplest way to do so. Everyone dials a number and in seconds they are talking to each other. In this post we'll build a conference line that anyone can join using Twilio and Ruby on Rails.
What you'll need
In order to build this conference line you will need:
- Ruby and Bundler installed
- A Twilio account (if you don't have one yet, sign up for a new Twilio account here and receive $10 credit when you upgrade)
- A Twilio phone number that can receive incoming calls
- ngrok for testing webhooks with our local application
With those tools gathered, we can get started.
Getting started with a Rails application
For this post we will create a new Rails app. If you want to add this capability to an existing application, you can skip over this part.
Install the latest version of Rails:
gem install rails
Generate a new Rails application. This application won't need a bunch of stuff that Rails brings with it by default, so I've skipped a few things here:
rails new --skip-action-mailer --skip-action-mailbox --skip-action-text --skip-active-record --skip-active-storage --skip-action-cable --skip-sprockets --skip-javascript --skip-turbolinks conference-calls-on-rails
cd conference-calls-on-rails
Run your new Rails app to make sure everything is working as expected.
./bin/rails server
Open localhost:3000
and you will see the new Rails application home page. This is what mine looks like:
Now that we have an application to work with let's get to work building our conference line.
Building the conference line
The conference line will require one controller with an action that will respond to an incoming webhook from Twilio when someone calls your Twilio number. We will respond to the request with TwiML to tell Twilio to send the caller into a conference call.
Dependencies
Start by adding the twilio-ruby
gem to the application Gemfile
:
gem 'bootsnap', '>= 1.4.2', require: false
gem 'twilio-ruby'
group :development, :test do
Install the new dependency with:
bundle install
Creating the controller
Next up, let's generate a new controller for our incoming calls. On the command line run:
./bin/rails generate controller calls create
This will create a CallsController
that will receive the webhook and return TwiML. It will also generate a route for us, but that route is not the one we want. Twilio webhooks are POST
requests by default, so let's make our route for a POST
request too. Open config/routes.rb
and change it to:
Rails.application.routes.draw do
resources :calls, only: [:create]
end
Now we need to update our CallsController
to return the TwiML to drop callers into a conference call. Open app/controllers/calls_controller.rb
.
The first thing in this file we need to do is skip the cross-site request forgery (CSRF) protection. The controller is intended to respond to incoming webhooks not from users, but from Twilio, so CSRF protection is unnecessary. Instead, check out this post on how to protect webhook endpoints in Ruby applications by validating the request signature using Rack middleware.
To skip the protection, add this to the top of the controller class:
class CallsController < ApplicationController
skip_before_action :verify_authenticity_token
def create
end
end
Now to build up the TwiML response as part of the create
action. We'll respond with a quick message to welcome the caller using <Say> then dial them into a conference room with <Dial> and <Conference>. We have to give the conference room a name so that everyone dialling in arrives in the same place. You can call yours whatever you like.
We'll build up the TwiML using the twilio-ruby
gem's Twilio::TwiML::VoiceResponse
class and then render it as XML.
class CallsController < ApplicationController
skip_before_action :verify_authenticity_token
def create
twiml = Twilio::TwiML::VoiceResponse.new
twiml.say(voice: 'alice', message: "Welcome to the conference call, let's dial you in right away.")
twiml.dial do |dial|
dial.conference('Thunderdome')
end
render xml: twiml
end
end
Run the application again and make a POST
request to localhost:3000/calls.You will see the TwiML returned as XML.
curl -X POST http://localhost:3000/calls
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say voice="alice">Welcome to the conference call, let's dial you in right away.</Say>
<Dial>
<Conference>Thunderdome</Conference>
</Dial>
</Response>
Testing with a real number
It's all very well making curl
requests, but we want to make sure this conference line works for real. To do so we'll need to open up our local development server to the internet so that it can receive webhook requests from Twilio. I recommend doing this with ngrok and here is how:
First start ngrok and point it to port 3000, which is the port the application server is listening on. You will need to pass the --host-header
argument with a value of "localhost:3000" too.
ngrok http 3000 --host-header "localhost:3000"
Now grab the ngrok URL that is generated for you. It should look like: https://NGROK_SUBDOMAIN.ngrok.io
. Open up the Twilio console and navigate to the phone number you want to use for this conference line. Enter the ngrok URL plus the path /calls
into the field labelled "When a call comes in".
Save the number, make sure your Rails application is still running, and give it a call from your phone. For extra credit, get someone else to call the number too, the holding music will end and you'll be chatting in your own conference line.
By the way, if you want to change the music you can do that using the waitUrl
attribute.
The power to conference call is in your hands
Now that you know how to build a conference line, you can start to add other features to it. Check out the Conference TwiML docs to learn how tojoin a Conference on mute, silently bridge calls, or build a moderated conference call.
If you want to check out the complete code for this application you can find it on GitHub. I'd love to hear what you're building with Twilio too, so do hit me up on Twitter at @philnash or drop me an email at philnash@twilio.com.