An easier way to write TwiML templates in Rails and Sinatra

November 05, 2014
Written by
Phil Nash
Twilion

sinatra

We recently had a discussion between some members of the Developer Evangelism team about how best to write TwiML within a Ruby application. There are a few methods available to a developer right now: handwrite the XML (ugh!), use the builder gem or take advantage of the twilio-ruby gem’s Twilio::TwiML::Response object.

Writing XML by hand can get messy very quickly. Building up a Twilio::TwiML::Response gets unwieldy within controller actions and violates the separation of concerns between controller and view. The builder gem is probably the best bet in a non-trivial application, but it also requires you to repeat yourself between templates as every TwiML response starts with a <Response> tag.

What if we could write just the code that generates the TwiML we need? And save it to a .twiml file, much like an .erb or .haml file, so that what we’re dealing with is obvious to every developer on the project?

Light bulb

At this point, I started to get excited about the idea. I found myself with a few hours spare and decided to tackle this problem by coding up what I think could be the best of both builder’s approach and Twilio::TwiML::Response’s handling of the repetition.

twiml_template is a gem that connects the Twilio::TwiML::Response object to the templating systems that Rails and Sinatra use. It does away with any boilerplate that any of the existing methods require, but still uses the Ruby standard builder template to create the XML for your TwiML response.

How do you use it?

Let’s code up a simple application to demonstrate how to use it! We are going to create ourselves a simple Rails application using TwiML to respond to an incoming call. First we’ll implement our TwiML using the Twilio::TwiML::Response class from the twilio-ruby gem. Then we’ll update that to use the builder gem and finally implement the simplest option, twiml_template. So, make sure you have your Twilio account details to hand and Ruby and Rails installed and let’s get started. Head to the command line and enter:

$ rails new twiml_template_test
$ cd twiml_template_test

A nice easy start. We generate a new Rails application for ourselves and cd to the application directory. Open the code up in your favourite text editor, navigate to the Gemfile and add the following line to the bottom:

gem 'twilio-ruby', '~> 3.13.1'

Back on the command line we need to get the twilio-ruby gem into our bundle, so we need to run:

$ bundle install

again. Wait for the gems to install. Now we’ll want to generate ourselves a controller, on the command line type:

$ rails generate controller Twilio voice

This is going to generate us a controller that will respond to Twilio’s requests for TwiML. Straight away we can remove the generated view as we won’t be needing that.

$ rm app/views/twilio/voice.html.erb

We also need to update the route that has been generated. Open the config/routes.rb file and change the line:

get 'twilio/voice'

to

post 'twilio/voice', defaults: { format: 'xml' }

This sets up our route and defaults the format to XML, since that is what we need to respond with to Twilio.

Now, open up the TwilioController. We are going to add a simple TwiML response to our controller action so that we can test this is all working over the phone. We also need to skip verifying the authenticity token so that Twilio can make POST requests to this action. Replace the contents of the file with the following code:

# app/controllers/twilio_controller.rb
class TwilioController < ApplicationController
  skip_before_filter :verify_authenticity_token

  def voice
    twiml = Twilio::TwiML::Response.new do |response|
     response.Say "Hello World!"
    end
    render xml: twiml.to_xml
  end
end

Ok, we’re ready to spin this up and test it. Start your rails server from the command line:

$ rails server

We’ll also need to expose our application to the outside world so that Twilio can access it. As ever, Kevin’s post on how to do this with ngrok is an invaluable source on how to do this. If you’ve got ngrok installed and ready, launch it now.

$ ngrok 3000

Grab your ngrok URL and head to your Twilio account. You’ll need to use an existing number you own, or buy a new one, and update the voice request URL to http://YOUR_NGROK_URL/twilio/voice.xml.

Enter your ngrok URL in the voice request URL field.

Save the updates to your number and give it a call. You should hear Twilio say “Hello World!” and then hang up. Good news! That works, but as I said earlier, that Twilio::TwiML::Response object is a bit unwieldy. Let’s replace that with builder.

Same app, different builder

For this, we need to create a view file. This is good as it is going to separate the different concerns of the controller and the view. Create a file called voice.xml.builder in the app/views/twilio folder. Now we can build up our TwiML with the builder. The view should look like this:

# app/views/twilio/voice.xml.builder
xml.instruct!
xml.Response do |response|
  response.Say "Hello World!"
end

Much neater. Now open up the TwilioController again and remove everything from within the voice action. The controller should end up looking like:

# app/controllers/twilio_controller.rb
class TwilioController < ApplicationController
  skip_before_filter :verify_authenticity_token

  def voice
  end
end

Let’s test again. Nothing on the Twilio side of things needs to change, just call your Twilio number again. Did you hear “Hello World!” again? Good, let’s improve this one more time.

Upgrading to twiml_template

First we need to add the twiml_template gem to our Gemfile. Open up the Gemfile again, and at the bottom add:

gem 'twiml_template', '~> 1.0'

On the command line, run:

$ bundle install

and we’re ready to tidy up our view even more. We need to update our route that we had generated, so return to the config/routes.rb file and change the default format to :twiml.

post 'twilio/voice', defaults: { format: 'twiml' }

Make sure you update the URL in your Twilio account too. You need to replace the .xml extension with .twiml.

enter_url_again

Finally, we need to update our view. Rename the file voice.xml.builder to voice.twiml and open it up for editing. Now comes the fun part: removing boilerplate. You can remove all the lines except for our Say verb, and change response to twiml. It should look like this:

# app/views/twilio/voice.twiml
twiml.Say "Hello World!"

Clear and simple. Let’s call our number up one more time to see if it still works. If you hear “Hello World!” one more time then you can relax knowing you never have to write boilerplate for TwiML ever again.

Less repetition, clearer code

I wanted to create a tool that made it easier for Ruby developers to generate TwiML within our applications. Including the twiml_template gem cleans up our templates and removes repetition.

The example above was simple, but for every extra endpoint you write TwiML for that’s one less time you have to instantiate a Twilio::TwiML::Response or write out the xml.instruct! command. All you need to do is write the TwiML you want to see in your application and let the template handle the rest.

If you want to get more of a feel for using twiml_template you can run and play with some simple Rails and Sinatra examples in the twiml_template_example repository. Or you can check out the source of twiml_template on GitHub');">[crayon-5b6d1e25801f0498904087-i/] on GitHub.

I’m really interested to know if this does make things simpler for rendering TwiML within your Ruby applications. Please install the gem, try it in your next Twilio project and let me know what you think. You can catch me on Twitter on @philnash or on email at philnash@twilio.com. Happy TwiML writing!