Migrating Your Ruby Application from Twilio SDK 4.x to 5.x

Deprecation notice: New functionality will only be added to the new library (Ruby Helper Library 5.x). The old library (4.x) will be officially supported until 10/15/2017. After that day, Twilio will stop providing bug fixes and Support might ask you to upgrade before debugging issues.

The Twilio Ruby Helper Library has undergone a number of changes from version 4.x to 5.x - we'll break down the major changes here to make migrating to the new version as painless as possible. If you're integrating Twilio in your Ruby app for the first time, you can skip straight to the install page.

Ruby Version Support

Note: twilio-ruby 5.x only supports Ruby 2.0+ due to both 1.8.x/1.9.x reaching End of Life.

Accessing Resources

# Old
call = @client.account.calls.get('CA123xxx')

# New
call = @client.api.v2010.account.calls('CA123xxx').fetch
## OR
call = @client.api.account.calls('CA123xxx').fetch

The new library makes Twilio API subdomains (Lookups, Conversations, Monitor, etc.) first-class citizens. You can now also pin your interactions to the Twilio API to specific versions of that API (so here, .v2010. ensures we always talk to the 2010-04-01 version of the API). This allows you to migrate portions of your code to future versions independently without having to do a full upgrade when you update the library.

You'll also notice you have to call fetch at the end to get the actual instance of a Call. This is because .calls('CAxxx') returns a "Context", which we can then fetch to retrieve an "Instance", with all of it's properties attached. This allows for better network efficiency and makes it more clear when the library is actually performing HTTP interactions.

> workspace = @client.taskrouter.workspaces('WSxxx')
#=> <WorkspaceContext ...>
> workspace.fetch
#=> <WorkspaceInstance status='active'...>

Listing Resources

There are now 2 ways to get a list of resources: list and stream.

  • list does exactly what it used to: it returns an Array that contains the Instances of resources.
> @client.api.account.messages.list
#=> [#<MessageInstance ..>, #<MessageInstance ..>, ...]
  • stream returns an Enumerable that can be passed to a block, it efficiently pages the list of resources for you and will pass limit amount of instances to the block (or every resource in the entire list, if no limit is set).
> @client.api.account.messages.stream(limit: 5) {|m| puts m.sid}
MS111xxx
MS222xxx
MS333xxx
MS444xxx
MS555xxx

Paging

The library now automatically handles paging for you! In both list and stream, you can specify the number of instances you want to grab (limit), the maximum size you want each page fetch to be (page_size), and the maximum amount of pages to fetch (page_limit). The library will then handle the rest for you (as efficiently as possible)!

@client.api.account.incoming_phone_numbers.stream(limit: 3000, page_size: 100) do |number|
  puts number.phone_number
end
> @client.conversations.completed.list(page_size: 100, page_limit: 10).size
#=> 1000

Proper Types

twilio-ruby resources now serialize/deserialize appropriate types. For example, in 4.x, a date would be represented as a String, leaving it up to you to serialize/deserialize strings into usable types. In 5.x, we deal with Time and Date objects:

# Old
feedback = @client.account.calls.feedback_summary.create(start_date: '2016-01-01', end_date: '2016-01-05')
feedback.start_date  #=> "2016-01-01"

# New
feedback = @client.api.account.calls.feedback_summary.create(start_date: Date.new(2016, 1, 1), end_date: Date.new(2016, 1, 5))
feedback.start_date  #=> #<Date 2016-01-01 ..>

Configurable HTTP Client

You can now plug your own HTTP client into the Twilio::REST client! Just make a wrapper that conforms to the Twilio::HTTP::HttpClient Interface. Then, pass an initialized object into the Twilio::REST::Client:

custom_client = MyCustomClient.new
@client = Twilio::REST::Client.new('ACxxx', 'AUTHTOKEN', http_client: custom_client)

Faraday is used by default, so you can also plug in any Faraday adapter:

@client.http_client.adapter = :typhoeus

Error handling

There are new classes to rescue errors from. The new library now uses the Twilio::REST::RestException class.

# Old
begin
  call = @client.account.calls.get('CA123xxx')
rescue Twilio::REST::RequestError => e
  logger.log(e.message)
end

# New
begin
  call = @client.account.calls('CA123xxx').fetch
rescue Twilio::REST::RestException => e
  logger.log(e.message)
end

TwiML Generation

You can now chain your calls to output simple TwiML. Here's an example:

require 'twilio-ruby'

response = Twilio::TwiML::VoiceResponse.new

def output_quick_polite_twiml():
  VoiceResponse.say('Hello!').hangup

There are now two responses types depending on what kind of response you want to output, VoiceResponse for all voice related verbs and MessagingResponse for everything message related.

You can find any voice verbs available as a method of a VoiceResponse instance. And you can set any attributes for those verbs using keyword arguments. All of them are using the underscore notation.

Loading Code Samples...
Language
SDK Version:
  • 5.x
Format:
  • TwiML
require 'twilio-ruby'

response = Twilio::TwiML::VoiceResponse.new
response.say('Chapeau!', voice: 'alice', language: 'fr-FR')

puts response
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Say voice="alice" language="fr-FR">Chapeau!</Say>
</Response>
Simple voice response saying "Chapeau!" in french

Nesting verbs are no longer using the with syntax, but instead, are append to a parent.

Loading Code Samples...
Language
SDK Version:
  • 5.x
Format:
  • TwiML
require 'twilio-ruby'

response = Twilio::TwiML::VoiceResponse.new
response.gather(action: '/process_gather.php', method: 'GET') do |gather|
    gather.say('Enter something, or not')
end
response.redirect('/process_gather.php?Digits=TIMEOUT', method: 'GET')

puts response
<?xml version="1.0" encoding="UTF-8"?>
<!-- page located at http://example.com/gather_hints.xml -->
<Response>
    <Gather action="/process_gather.php" method="GET">
        <Say>Enter something, or not</Say>
    </Gather>
    <Redirect method="GET">
        /process_gather.php?Digits=TIMEOUT
    </Redirect>
</Response>
Nesting a Gather verb in a voice response

The same changes apply to MessagingResponse:

Loading Code Samples...
Language
SDK Version:
  • 5.x
Format:
  • TwiML
require 'twilio-ruby'

response = Twilio::TwiML::MessagingResponse.new
response.message(body: 'Store Location: 123 Easy St.')

puts response
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message>
        Store Location: 123 Easy St.
    </Message>
</Response>
Simple sending of SMS

And a nested example:

Loading Code Samples...
Language
SDK Version:
  • 5.x
Format:
  • TwiML
require 'twilio-ruby'

response = Twilio::TwiML::MessagingResponse.new
response.message do |message|
    message.body('Store Location: 123 Easy St.')
    message.media('https://demo.twilio.com/owl.png')
end

puts response
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message>
        <Body>Store Location: 123 Easy St.</Body>
        <Media>https://demo.twilio.com/owl.png</Media>
    </Message>
</Response>
Sending of an Message with Media (MMS)

Debugging API Requests

To assist with debugging, the library allows you to access the underlying request and response objects. This capability is built into the default HTTP client that ships with the library.

For example, you can retrieve the status code of the last response like so:

require 'rubygems' # not necessary with ruby 1.9 but included for completeness
require 'twilio-ruby'

# put your own credentials here
account_sid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
auth_token = 'your_auth_token'

# set up a client to talk to the Twilio REST API
@client = Twilio::REST::Client.new(account_sid, auth_token)

@message = @client.messages.create(
  to: '+14158675309',
  from: '+14258675310',
  body: 'Ahoy!'
)

# Retrieve the status code of the last response from the HTTP client
puts @client.http_client.last_response.status_code

Where to Find Help

All of the Quickstarts, Tutorials, and API Reference documentation will have example code in both the older 4.x library and the new 5.x library. There are hundreds of samples just waiting for you to copy and paste.

The Twilio Ruby helper library is open source software. Please visit us on GitHub to view the source, open issues, or submit pull requests.
Finally, know we are always ready to help! Just contact us directly for support.

Need some help?

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd browsing the Twilio tag on Stack Overflow.

1 / 1
Loading Code Samples...
SDK Version:
  • 5.x
Format:
  • TwiML
require 'twilio-ruby'

response = Twilio::TwiML::VoiceResponse.new
response.say('Chapeau!', voice: 'alice', language: 'fr-FR')

puts response
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Say voice="alice" language="fr-FR">Chapeau!</Say>
</Response>
SDK Version:
  • 5.x
Format:
  • TwiML
require 'twilio-ruby'

response = Twilio::TwiML::VoiceResponse.new
response.gather(action: '/process_gather.php', method: 'GET') do |gather|
    gather.say('Enter something, or not')
end
response.redirect('/process_gather.php?Digits=TIMEOUT', method: 'GET')

puts response
<?xml version="1.0" encoding="UTF-8"?>
<!-- page located at http://example.com/gather_hints.xml -->
<Response>
    <Gather action="/process_gather.php" method="GET">
        <Say>Enter something, or not</Say>
    </Gather>
    <Redirect method="GET">
        /process_gather.php?Digits=TIMEOUT
    </Redirect>
</Response>
SDK Version:
  • 5.x
Format:
  • TwiML
require 'twilio-ruby'

response = Twilio::TwiML::MessagingResponse.new
response.message(body: 'Store Location: 123 Easy St.')

puts response
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message>
        Store Location: 123 Easy St.
    </Message>
</Response>
SDK Version:
  • 5.x
Format:
  • TwiML
require 'twilio-ruby'

response = Twilio::TwiML::MessagingResponse.new
response.message do |message|
    message.body('Store Location: 123 Easy St.')
    message.media('https://demo.twilio.com/owl.png')
end

puts response
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message>
        <Body>Store Location: 123 Easy St.</Body>
        <Media>https://demo.twilio.com/owl.png</Media>
    </Message>
</Response>