When my ruby script makes outgoing calls through Twilio, it's a piece of cake for me to find, output, and reuse the Call Sid for later as such :
#client = Twilio::REST:Client.new account_sid, auth_token
call = #client.account.calls.create({ :from=>'INC', :to=>'OUT', :url=>'URL', :method=>'GET'})
puts call.sid
This works fine for outgoing calls that I make myself.
The issue is when I try to get the call SID for incoming calls.
get '/greeting' do
Twilio::TwiML::Response.new do |r|
r.Say 'Hello. Welcome.'
r.Gather :numDigits => '1', :action => '/greeting/handle-gather', :method => 'get' do |g|
g.Say 'For X, press 1. For Y, press 2. For Z, press 3.'
end
end.text
puts Twilio::TwiML::Request.CallSid
CallSid = incoming_Cid
end
The incoming_Cid is then stored in a MYSQL database for later. I'm not sure if Twilio::TwiML::Request.CallSid is the correct way to get the request parameters that Twilio passes to my application.
How would I properly retrieve the CallSid for incoming calls?
Nevermind, the issue was been solved by simply using Ruby's params instead of the Twilio HTTP Request object:
puts params['CallSid']
Related
I'm using opal-jquery to send an ajax request to my backend, but the json payload is malformed when I try to access it on the backend.
When I do puts #params.to_s on my back end, it gets displays as:
{"{\"username\":\"some_user\", \"password\":\"some_password\"}"=>nil}
So to get the login details I have to do:
#params.each do |k,v|
login_details = JSON.parse(k)
end
My front end (opal) submit request looks like this:
def handle_login_submit details
url = "/client/api/auth"
HTTP.post url, payload: details.to_json, dataType: 'json' do |response|
case response.status_code / 100
when 2
puts response.status_code
self.login_state = :return_success
puts response.json
when 4
self.login_state = :return_failed
puts response.status_code
puts response.json
when 5
self.f_message = {type: :error, message: "There was a server error" }
self.login_state = :return_failed
end
end
end
I definitely know that details is correctly formatted so that's not an issue.
I guess in the end, it boils down to is whether it's
opal-jquery sending the post request incorrectly
sinatra improperly parsing the request.
I'm not sure which one it is, but I'm inclined to believe it's the former because it was working fine before I switched to using react.rb for the front end.
After following the advice from this, specifically I'm doing:
before do
request.body.rewind
req = request.body.read
puts req
puts JSON.parse(req)
end
I was able to see that the request arrived at the server correctly and as expected. I don't know why but sinatra was mangling the response in such a away that #params came out as
{"{\"username\":\"some_user\", \"password\":\"some_password\"}"=>nil}
so, in the end I'm doing
before do
request.body.rewind
#request_payload = JSON.parse(request.body.read)
request.body.rewind
end
To read out the request body before sinatra gets anything and just reading out the params I need from #request_payload.
I am working on a project that returns SMS messages to a user who has just sent a SMS message to the server.
The process is:
The user sends a SMS message to the server.
The server will send two SMS messages back to this user. Note that these are two separate short messages and will be sent pretty much at the same time.
I've got the sending part working, but just for sending one SMS message, not two. When I add more code to send another message only the second message part works, which means only the second message has been sent out, the first message has been ignored.
The code looks pretty much like:
else
sms = SMS.create(:body => params['Body'], :from => params['From'], :to => params['To'], :created_at => Time.now)
#return a random saved sms
return_secret = SMS.first(:offset => rand(SMS.count))
twiml = Twilio::TwiML::Response.new do |r|
r.Sms return_secret.body
#send another message to remind user for rating
ask_rating = remind_rating
if ask_rating
twiml = Twilio::TwiML::Response.new do |r|
r.Sms ask_rating
end
twiml.text
end
Does anyone know how to send two messages in Twilio?
You've got some variable shadowing going on with twiml. As you wrote it, the second message's code is inside of the first message's block. Yet, you refer to a variable with the same name as one outside of the block. I would try flattening your code so you aren't nesting like that.
I think the issue here is you're instantiating a second TwiML::Response object when you already have one, so you can just references the previous one which you assigned to r in the first block. You also called it r in the second block so you just remove the block that encloses it:
sms = SMS.create(:body => params['Body'], :from => params['From'], :to => params['To'], :created_at => Time.now)
#return a random saved sms
return_secret = SMS.first(:offset => rand(SMS.count))
twiml = Twilio::TwiML::Response.new do |r|
r.Sms return_secret.body
#send another message to remind user for rating
ask_rating = remind_rating
if ask_rating
r.Sms ask_rating
end
end
Also the blocks weren't balanced in the initial code snippet so I stripped out the else to make it syntactically accurate.
Thank you all, really appreciate your replies.
After consulting with twilio team, they gave me an example like this:
require 'rubygems'
require 'twilio-ruby'
require 'sinatra'
get '/sms-quickstart' do
twiml = Twilio::TwiML::Response.new do |r|
r.Message "Hey Monkey. Thanks for the message!"
r.Message "this is the 2nd message"
end
twiml.text
end
I just deleted
if ask_rating
twiml = Twilio::TwiML::Response.new do |r|
everything works...
I am building a Ruby app using Sinatra and the Twilio api.
Over a phone call to my assigned Twilio number, the user gets prompted to record an audio message. Once that message is recored the user gets redirected to the following route where if the user dials 1 (or anything else), they should get redirected to their feed of msgs, but if the user dials 2, then the user's message gets deleted and should get redirected to a route where they can record a new message.
Here is my route:
get '/playback/handle-recording/:recordingSID' do
if params['Digits'] = '2'
delete(params['recordingSID'])
deletedMsg = "Audio deleted."
getRecord(deletedMsg)
else
getFeed()
end
end
helper methods:
helpers do
def delete(recording)
recording = client().account.recordings.get(recording)
recording.delete
end
def getFeed()
redirect '/feed'
end
def getRecord(appendMsg)
Twilio::TwiML::Response.new do |response|
if appendMsg
response.Say appendMsg
end
response.Say "Record your message."
response.Record :maxLength => '5', :trim => "trim-silence", :playBeep => "true", :action => '/playback', :method => 'get'
end.text
end
end
My issue is that whether the user lands in the "if" or the "else" the first method, getRecord(deletedMsg) is the one that gets called, and not the getFeed().
How can I fix my route so that if the user lands in the else he does get redirected to his feed page and not to the getRecords method.
Are you sure they're actually making it into the else? Ruby won't just randomly not execute what's in there for no good reason.
One thing you may want to look at is you are assigning, not comparing the params value:
if params['Digits'] = '2'
You'll want to do:
if params['Digits'] == '2'
That could definitely lead to some strange behavior in an if statement, like, for instance always executing one path.
I would like to do the following:
Call my twilio number from my cell phone
My twilio number identifies the incoming number then immediately hangs up
My twilio number calls back the identified number (my cell phone number)
When I pick up, twilio asks me to enter the number I wish to call
Twilio gathers the input of the number I want to call and connects me.
So I can make cheap international calls (or roaming calls) from my cell phone.
So far, taken from the twilio website api docs, I have:
require 'rubygems'
require 'sinatra'
require 'twilio-ruby'
get '/' do
account_sid = 'xxxxxxx'
auth_token = 'zzzzzzz'
to = params['From']
#to = '+447928344246'
#to = '441903773807'
from = '442033222327'
Twilio::TwiML::Response.new do |r|
r.Hangup
end.text
# set up a client to talk to the Twilio REST API
#client = Twilio::REST::Client.new account_sid, auth_token
#call = #client.account.calls.create(
:from => from, # From your Twilio number
:to => to, # To any number
:timeout => "20",
# Fetch instructions from this URL when the call connects
:url => 'https://dl.dropboxusercontent.com/u/85088004/twilio/twilio.xml'
)
end
post '/makecall' do
warn params.inspect
account_sid = ' ACaf2b951ae6f7424da036ea9dcd5b0d91'
auth_token = 'my token'
#client = Twilio::REST::Client.new account_sid, auth_token
call = #client.account.calls.create(:url => "https://dl.dropboxusercontent.com/u/85088004/twilio/callback.xml",
:to => params[:Digits],
:from => "+442033222327")
puts call.to
end
The twilio.xml, in the '/' section url file is:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Gather action="/makecall" method="POST">
<Say timeout="10">Enter the number you wish to call</Say>
</Gather>
</Response>
I get "Sorry an application error has occurred." Then it just hangs up.
warn params.inspect
does not produce anything when I inspect the heroku logs. So I think (one of) the problem(s) is that the params of the number I am dialling is not passed.
Is there any other problem with logic or scripting that seems obvious?
Does the problem lie with the url in the '/makecall' snippet? It si:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
</Hangup>
</Response>
Many, many thanks!
SOLVED!! Thank you for help from the T evangelist. Here is the solution:
require 'rubygems'
require 'sinatra'
require 'twilio-ruby'
account_sid = 'my sid'
auth_token = 'my token'
get '/' do
from = 'my T number'
to = params[:From]
Twilio::TwiML::Response.new do |r|
r.Hangup
end.text
sleep 10
# set up a client to talk to the Twilio REST API
#client = Twilio::REST::Client.new account_sid, auth_token
#call = #client.account.calls.create(
:from => from, # From your Twilio number
:to => to, # To any number
# Fetch instructions from this URL when the call connects
:url => 'https://dl.dropboxusercontent.com/u/85088004/twilio/twilio.xml'
)
end
# the xml file. It is VERY IMPORTANT that you have the absolute url in the action=""
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Gather timeout="20" action="http://dry-journey-9071.herokuapp.com/makecall" method="GET">
<Say voice="alice">Enter the destination number, please.</Say>
</Gather>
<Say voice="alice">Input not received. Thank you</Say>
</Response>
#Back to the app:
get '/makecall' do
number = params[:Digits]
Twilio::TwiML::Response.new do |r|
r.Dial number ### Connect the caller to Koko, or your cell
r.Say 'The call failed or the remote party hung up. Goodbye.'
end.text
end
Yay!
Twilio Developer Evangelist here.
When you detect that it is your own number, you want to return some TwiML (XML) to Twilio, this should suffice: <Response> <Hangup/> </Response>
You would then need to make a REST API call to Twilio to make a new outbound call to yourself:
#client.account.calls.create(to: my_number, from: "+sometiwilionumber", url: "http://example.com/make-other-call-twiml")
Then use the URL of some TwiML to <Gather> the number you want to dial, and simply <Dial> to that number...
The thing you want to avoid is having Twilio call you back before the first call ends. As you will need to make the API call first, we need to use threading to get around it. I'm not bad with Ruby/Sinatra, but I'm no expert with threading here, but this should work:
twilio_call_thread = Thread.new{
sleep 3 #3 Seconds should be plenty, but you may want to experiment.
#client.account.calls.create(to: mynumber, from: some_twilio_number, url: "http://example.com/gather-and-dial")
}
#Then return the TwiML to hangup...
"<Response><Hangup/></Response>"
You call your number, it creates a thread, then goes to sleep. It responds with a <Hangup> to disconnect the call. A few seconds later, the thread wakes up and you'll get the return call. You will need some TwiML on that call to do a <Gather> to get the phone number to dial, and then <Dial> to make the actual call.
I wasn't sure about the threading, so before checking on that, I had two other ideas you could use:
Use SMS. Send you Twilio number the other number you want to dial, and just have Twilio make the call directly between your number, and the other number.
Secondly, just use a URL, presuming you have data on your phone you can just open a URL which does the same without the initial call or SMS.
Oh - and a third option, if you don't want to muck about with threads, or that's not working for you: set the Status Callback URL on your Twilio number (click 'Optional Voice Settings'). This is fired after the call completes, and from there you can make the new call to yourself.
Hope you get it sorted, it's going to be awesome.
When I receive a call, I output the CallSid parameter and save it as a variable #incoming_Cid to track the call throughout it's duration and manipulate it.
When I try to bridge the call in between a customer and an employee, I dial a conference. I'd like to use the #incoming_Cid as the friendly name to make the conference unique every time.
Example:
puts params['CallSid']
#incoming_Cid = params['CallSid']
Twilio::TwiML::Response.new do |r|
r.Dial :action => '/greeting/handle-gather/techsupp/conference', :method => 'get' do |d|
d.Say 'Please wait while we connect you to one of our operators. '
d.Conference "#{incoming_Cid}"
end
end
Normally, I have the friendly name in ' ', but string interpolation requires " ". So I'm not sure if what I'm trying to do is correct/allowed?
Also, how can I output the sid params of a dialed conference like described here.
You are definitely going in the right direction here.
There are a few suggestions I would make to accomplish what you are going for. Here is my modified snippet:
puts params['CallSid']
#incoming_Cid = params['CallSid']
response = Twilio::TwiML::Response.new do |r|
r.Dial :action => '/greeting/handle-gather/techsupp/conference', :method => 'get' do |d|
d.Say 'Please wait while we connect you to one of our operators. '
d.Conference #incoming_Cid
end
end
puts response.text
The changes I made are assigning your TwiML::Response to the response variable and outputting the TwiML text at the end which will be your generated XML response.
I also changed your d.Conference line to simply output #incoming_Cid without putting it in quotes, which in this case should work as valid Ruby.
Hope this helps!