34
RUBY ON THE PHONE Mat Schaffer, Ruby Nation 2011

Ruby on the Phone

Embed Size (px)

Citation preview

Page 1: Ruby on the Phone

RUBY ON THE PHONEMat Schaffer, Ruby Nation 2011

Page 2: Ruby on the Phone

MAT SCHAFFER

github.com/matschaffer

@matschaffer

Page 3: Ruby on the Phone

RAILS – JAVASCRIPT(for hire)

Page 4: Ruby on the Phone

CALLME

Page 5: Ruby on the Phone

•Provider comparison

•Making phone calls

•Handling Call flow

•SMS

•Testing

Page 6: Ruby on the Phone

JSON REST API

they host a JVM script

IM and Twitter integration

3¢ per minute

$3 per month per line

XML REST API

you generate TwiML

just phone and SMS

1¢/2¢ per minute

$1 per month per line

Page 7: Ruby on the Phone

PLACING CALLS

Page 8: Ruby on the Phone

https://github.com/webficient/twilio

require 'rubygems'require 'twilio'

Twilio.connect(ENV['TWILIO_SID'], ENV['TWILIO_TOKEN'])Twilio::Call.make('+12155551213',                  '+12155551234',                  'http://myapp.com')

From*

ToWhat do to

Page 9: Ruby on the Phone

> curl -d From=+12155551212 \       -d To=+12155551234 \       -d Url=http://myapp.com \       -u $TWILIO_SID:$TWILIO_TOKEN \https://api.twilio.com/2010-04-01/Accounts/$TWILIO_SID/Calls

Page 10: Ruby on the Phone

POST https://twilio/callUrl=http://me/calls

POST https://me/callsCallSid=CAc7ca63fb9...

Page 11: Ruby on the Phone

<?xml version="1.0" encoding="UTF-8" ?><Response>  <Say>Hello Ruby Nation</Say></Response>

Page 12: Ruby on the Phone

INCOMING CALLS

Page 13: Ruby on the Phone
Page 14: Ruby on the Phone

require 'rubygems'require 'twilio'

Twilio.connect(ENV['TWILIO_SID'], ENV['TWILIO_TOKEN'])resp = Twilio::AvailablePhoneNumbers.search_local(:postal_code => '20191')numbers = resp['TwilioResponse']['AvailablePhoneNumbers']['AvailablePhoneNumber']

my_number = numbers.firstTwilio::IncomingPhoneNumber.create(:PhoneNumber => my_number['PhoneNumber'],                                   :VoiceUrl => 'http://myapp.com')

Page 15: Ruby on the Phone
Page 16: Ruby on the Phone

<?xml version="1.0" encoding="UTF-8"?><Response>  <Say>Welcome to the party!</Say>  <Dial>    <Conference>rubynation_partyline</Conference>  </Dial></Response>

For a good time call (540) 318-2266

post '/' do  return Twilio::Verb.new do |v|    v.say "Welcome to the party!"    v.dial do      v.conference 'rubynation_partyline'    end  end.responseend

Page 17: Ruby on the Phone
Page 18: Ruby on the Phone

TWIML

Page 19: Ruby on the Phone

VERBS

OUTPUT <Play> <Say>

INPUT <Gather> <Record>

CALLS <Dial><Number> <Conference>

<Dial><Number> <Conference>

OTHERS <Hangup> <Reject> <Pause> <Redirect> <Sms>

Page 20: Ruby on the Phone

WHOOPS! RAILS ISSUES

• skip_before_filter :verify_authenticity_token

• be careful about response types (use *.xml or filter)

• tough to fit in RESTful model

Page 21: Ruby on the Phone

CALL FLOW

Page 22: Ruby on the Phone

TWILIO LOOP

1.Post initial call information with new CallSid

2.Perform action

3.Post action’s result with original CallSid

4.Repeat

Page 23: Ruby on the Phone

<?xml version="1.0" encoding="UTF-8"?><Response> <Gather action="/calls/response.xml"> "<Say>Hi there, press a number</Say> </Gather></Response>

<?xml version="1.0" encoding="UTF-8"?><Response> <Say>Thanks for your input</Say></Response>

Page 24: Ruby on the Phone

<?xml version="1.0" encoding="UTF-8"?><Response> <Dial action="/calls/complete.xml"> " <Number url="/calls/prompt.xml?connection_id=1">2155551212</Number> </Dial></Response>

<?xml version="1.0" encoding="UTF-8"?><Response> <Say> Here’s what the called person hears </Say></Response>

<?xml version="1.0" encoding="UTF-8"?><Response> <Say>The caller hears this after the call</Say></Response>

Page 25: Ruby on the Phone

SMS

Page 26: Ruby on the Phone

require 'rubygems'require 'twilio'

Twilio.connect(ENV['TWILIO_SID'], ENV['TWILIO_TOKEN'])Twilio::Sms.message('+12155551213',                    '+12155551234',                    "Hello sms")

SENDING

Page 27: Ruby on the Phone

RECEIVINGrequire 'rubygems'require 'sinatra'require 'twilio'

post '/sms' do  return Twilio::Verb.new do |v|    v.sms "Ohai #{params[:From]}"  end.responseend

<?xml version="1.0" encoding="UTF-8"?><Response>  <Sms>Ohai +12155551212</Sms></Response>

Page 28: Ruby on the Phone

TESTING

Page 29: Ruby on the Phone

REST CALL TESTING

• Mocking: Mocha, Rspec, etc

• HTTP Mocking: VCR, Artiface, FakeWeb, WebMock

Page 30: Ruby on the Phone

Artifice.activate_with(FakeTwilio)

require 'rubygems'require 'sinatra'

class FakeTwilio < Sinatra::Base  def fixture(resource)    resource.gsub!('/', '-')    Rails.root.join('test', 'support', 'twilio_responses', "#{resource}-GET.xml").read  end

  get '/2010-04-01/Accounts/:sid/*' do |sid, resource|    fixture(resource)  end

  post '/2010-04-01/Accounts/:sid/*' do |sid, resource|    fixture(resource)  endend

Page 31: Ruby on the Phone

ARTIFICE + CUCUMBER

module Selenium  Net = ::Net.dup  module Net    HTTP = Artifice::NET_HTTP  endend

class Capybara::Server  Net = ::Net.dup  module Net    HTTP = Artifice::NET_HTTP  endend

Kinda sucked. got better?

Page 32: Ruby on the Phone

TWIML TESTING

  test "new should omit connected connections" do    @connection.connect!    post :new, :CallSid => @sid    assert_match "Number", response.body    assert_not_match @connection.number, response.body  end

Basic match testing

Page 33: Ruby on the Phone

NEED MORE INPUT?

Page 34: Ruby on the Phone

THANK YOUquestions?