Upload
mat-schaffer
View
1.790
Download
2
Tags:
Embed Size (px)
Citation preview
RUBY ON THE PHONEMat Schaffer, Ruby Nation 2011
MAT SCHAFFER
github.com/matschaffer
@matschaffer
RAILS – JAVASCRIPT(for hire)
CALLME
•Provider comparison
•Making phone calls
•Handling Call flow
•SMS
•Testing
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
PLACING CALLS
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
> 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
POST https://twilio/callUrl=http://me/calls
POST https://me/callsCallSid=CAc7ca63fb9...
<?xml version="1.0" encoding="UTF-8" ?><Response> <Say>Hello Ruby Nation</Say></Response>
INCOMING CALLS
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')
<?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
TWIML
VERBS
OUTPUT <Play> <Say>
INPUT <Gather> <Record>
CALLS <Dial><Number> <Conference>
<Dial><Number> <Conference>
OTHERS <Hangup> <Reject> <Pause> <Redirect> <Sms>
WHOOPS! RAILS ISSUES
• skip_before_filter :verify_authenticity_token
• be careful about response types (use *.xml or filter)
• tough to fit in RESTful model
CALL FLOW
TWILIO LOOP
1.Post initial call information with new CallSid
2.Perform action
3.Post action’s result with original CallSid
4.Repeat
<?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>
<?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>
SMS
require 'rubygems'require 'twilio'
Twilio.connect(ENV['TWILIO_SID'], ENV['TWILIO_TOKEN'])Twilio::Sms.message('+12155551213', '+12155551234', "Hello sms")
SENDING
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>
TESTING
REST CALL TESTING
• Mocking: Mocha, Rspec, etc
• HTTP Mocking: VCR, Artiface, FakeWeb, WebMock
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
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?
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
NEED MORE INPUT?
THANK YOUquestions?