How to build a conference line with Twilio and Ruby

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:

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:

The page that shows Rails is running. My Rails version is 6.0.2.2 and Ruby version 2.7.0.

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".

Enter your webhook URL in the field marked "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.

No Comments Yet