Sean’s Obsessions

Sean Walberg’s blog

Twilio Client Quickstart - in Ruby

I’ve wanted to play with the Twilio client for a while. They have this great quick start but it’s written in PHP. Now I don’t mind PHP, but I prefer Ruby. If I’m going to write anything using the client, it’s going to be in Ruby, so I don’t see the point in learning it on PHP.

So, here is the meat of the quickstart done up as a Rails 3.1 application.

First, generate the application.

1
2
3
4
5
6
7
8
9
$ rails new twilio
      create
      create  README
      create  Rakefile
      create  config.ru
      create  .gitignore
      create  Gemfile
      create  app
      ...

This creates a new Rails 3.1 app in the current directory called twilio. Change to this directory, and add a line to your Gemfile:

Gemfile
1
gem 'twilio-ruby'

Run bundle install to add the official Twilio gem to your bundle.

Next, head on over to your Twilio account and get your SID and auth token. Those can go in an initializer, config/initializers/twilio.rb:

config/initializers/twilio.rb
1
2
TwilioAccountSID="AC........"
TwilioAuthToken="......."

Those are the magic tokens that let you authenticate yourself to the Twilio API, and more importantly for them, let them bill you.

Next, head on over to app/helpers/application_helper.rb:

app/helpers/application_helper.rb
1
2
3
4
5
module ApplicationHelper
  def twilio_javascript_include_tag
    javascript_include_tag "http://static.twilio.com/libs/twiliojs/1.0/twilio.min.js"
  end
end

Then in app/views/layouts/application.html.erb add that helper in the head:

app/views/layouts/application.html.erb
1
2
3
4
5
<pre><code>
  <%= stylesheet_link_tag    "application" %>
  <%= javascript_include_tag "application" %>
  <%= twilio_javascript_include_tag  %>
  <%= csrf_meta_tags %><br />

Yea, you could have put the code right in the layout, but I like sparse layout files.

Next up, create a controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ rails generate controller client index
      create  app/controllers/client_controller.rb
       route  get "client/index"
      invoke  erb
      create    app/views/client
      create    app/views/client/index.html.erb
      invoke  test_unit
      create    test/functional/client_controller_test.rb
      invoke  helper
      create    app/helpers/client_helper.rb
      invoke    test_unit
      create      test/unit/helpers/client_helper_test.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/client.js.coffee
      invoke    scss
      create      app/assets/stylesheets/client.css.scss

Then add root :to => ‘client#index’ to config/routes.rb so that your new view is displayed in the root url.

Run rails server or whatever you do to start your dev instance and browse to it. You should get the usual “find me in app/views/client/index.html.erb” message. Check the headers to make sure the library is being installed. The rest of the examples then deal with app/views/client/index.html.erb and app/helpers/client_helper.rb.

For the first example you want:


Helper
1
2
3
4
5
6
7
module ClientHelper
  def twilio_token
    capability = Twilio::Util::Capability.new TwilioAccountSID, TwilioAuthToken
    capability.allow_client_outgoing "APabe7650f654fc34655fc81ae71caa3ff"
    capability.generate
  end
end
View
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<%= javascript_tag do %>
function call() {
  Twilio.Device.connect();
}
function hangup() {
  Twilio.Device.disconnectAll();
}
$(function() {
  Twilio.Device.setup("<%= twilio_token %>");
Twilio.Device.ready(function (device) {
    $("#log").text("Ready");
  });
Twilio.Device.error(function (error) {
    $("#log").text("Error: " + error.message);
  });
Twilio.Device.connect(function (conn) {
    $("#log").text("Successfully established call");
  });
});
<% end %>
<button class="call" onclick="call();">
  Call
</button>

For the second example, you just change the view.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<%= javascript_tag do %>
function call() {
  Twilio.Device.connect();
}
function hangup() {
  Twilio.Device.disconnectAll();
}
$(function() {
  Twilio.Device.setup("<%= twilio_token %>");
Twilio.Device.ready(function (device) {
    $("#log").text("Ready");
  });
Twilio.Device.error(function (error) {
    $("#log").text("Error: " + error.message);
  });
Twilio.Device.disconnect(function (conn) {
    $("#log").text("Call ended");
  });
Twilio.Device.connect(function (conn) {
    $("#log").text("Successfully established call");
  });
});
<% end %>
<button class="call" onclick="call();">
  Call
</button>
<button class="hangup" onclick="hangup();">
  Hangup
</button>
<div id="log">Loading pigeons...</div>

For the third example we’ll have to change the helper and the view accordingly:

app/helpers/client_helper.rb (note I’m using my own sandbox id. You get your own inside the Twilio account page!)

1
2
3
4
5
6
7
8
module ClientHelper
  def twilio_token
    capability = Twilio::Util::Capability.new TwilioAccountSID, TwilioAuthToken
    capability.allow_client_outgoing "AP..."
    capability.allow_client_incoming 'jenny'
    capability.generate
  end
end
app/views/client/index.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<%= javascript_tag do %>
function call() {
  Twilio.Device.connect();
}
function hangup() {
  Twilio.Device.disconnectAll();
}
$(function() {
  Twilio.Device.setup("<%= twilio_token %>");
Twilio.Device.ready(function (device) {
    $("#log").text("Ready");
  });
Twilio.Device.error(function (error) {
    $("#log").text("Error: " + error.message);
  });
Twilio.Device.disconnect(function (conn) {
    $("#log").text("Call ended");
  });
Twilio.Device.connect(function (conn) {
    $("#log").text("Successfully established call");
  });
Twilio.Device.incoming(function (conn) {
    $("#log").text("Incoming connection from " + conn.parameters.From);
    // accept the incoming connection and start two-way audio
    conn.accept();
  });
});
<% end %>
<button class="call" onclick="call();">
  Call
</button>
<button class="hangup" onclick="hangup();">
  Hangup
</button>
<div id="log">Loading pigeons...</div>

Now, hook up a new action in the client controller to redirect the call from Twilio to the app inside app/controllers/client_controller.rb

1
2
3
4
5
6
7
8
def incoming
  response = Twilio::TwiML::Response.new do |r|
    r.Dial  do |d|
      d.Client 'jenny'
    end
  end
  render :text => response.text
end

Don’t forget to add post “client/incoming” to config/routes.rb. Then point your sandbox URL to your dev box, such as http://yourhome.com:3000/client/incoming.xml.

As a bonus, here’s a rake task to log in to a remote host and set up an ssh tunnel on remote port 3000 to local port 3000:

Rakefile
1
2
3
4
5
6
7
8
9
10
11
12
13
namespace :tunnel do
  desc "Start a ssh tunnel"
  task :start => :environment do
    public_host_username = "sean"
    public_host = "home.ertw.com"
    public_port = 3000
    local_port = 3000
    puts "Starting tunnel #{public_host}:#{public_port} \
          to 127.0.0.1:#{local_port}"
    exec "ssh -nNT -g -R *:#{public_port}:127.0.0.1:#{local_port} \
                           #{public_host_username}@#{public_host}"
  end
end

There are two more examples in the quickstart, but as they are more of the same, I’ll leave them for another post. I’d also like to try rewriting the Javascript in Coffeescript.

Update - Code is at https://github.com/swalberg/twilio-client-ruby

Comments

I’m trying something new here. Talk to me on Twitter with the button above, please.