How do I dynamically generate TwiML from my Rails app? - ruby-on-rails

I have integrated Twilio through twilio-ruby
with my Rails app. The basic SMS and voice capabilities are working as expected, but now I want to extend my functionality. I would like to be able to generate TwiML in my controller dynamically, save it somewhere (either locally or to a service), and then have Twilio access this XML. For example, a customer makes an order through my app, TwiML is generated and saved, and then Twilio makes a voice call to my supplier with the new order data. Keeping concurrent orders in mind, what might the solution look like for this? What is the best solution for storing the TwiML/XML and then having Twilio access it? Thank you.

Dynamically generating the TwiML during the call does seem like it would be the preferred method.
An example of generating TwimL content dynamically from the docs where we greet a caller by name:
https://www.twilio.com/docs/quickstart/ruby/twiml/greet-caller-by-name#twiml-quickstartrb
require 'rubygems'
require 'sinatra'
require 'twilio-ruby'
get '/hello-monkey' do
people = {
'+14158675309' => 'Curious George',
'+14158675310' => 'Boots',
'+14158675311' => 'Virgil',
'+14158675312' => 'Marcel',
}
name = people[params['From']] || 'Monkey'
Twilio::TwiML::Response.new do |r|
r.Say "Hello #{name}"
end.text
end
Instead of a people array your application would have to parse incoming message bodies (if using SMS) for the order and then make the appropriate call to the supplier.
If however, your use case truly requires creating hosted TwiML on the fly, TwiML Bins in the Twilio Console will soon allow you to do this with interpolation.
That means you would be able to do something like:
curl -X POST api.twilio.com/..../Calls -d 'Url=https://hander.twilio.com/EHxxx?message=hello+world' -u Cxxx:yyyy
And your TwiML Bin would contain the necessary TwiML:
<Response><Say>{{message}}</Say></Response>
This way, you would not need to make two rest calls and wouldn't amass thousands (or more) of redundant bins that will be unwieldy to maintain or clean up.

Related

Any easy ways to group the emails together into a thread using Rails ActionMailer?

I want the emails sent from my Rails app to the users to be grouped into threads in some conditions, like the emails from GitHub do. (in Gmail and Outlook.)
I know that needs the emails having specific Message-IDs in In-Reply-To or References email headers.
Do I have to manage all the Message-IDs in the database? Or is there smarter ways to to that in Ruby on Rails?
I want to know the best practice to threadify emails in Rails.
There is no need to keep track of the Message-ID in the database.
The only thing you need is a method that generates the same Message-ID for the same input (for example an md5 hash). And the input of that method must be something that does not change and identifies all messages that should be grouped together. In your example with the grouped emails from GitHub about specific pull requests, they could have used the id as an input.
I would start to play around with something like this:
require 'digets'
def message_id(identifer)
Digest::MD5.hexdigest(identifer)
end
message_id("pull-123")
#=> "23172d2caceae88a1152e967af71fc6e"
message_id("issue-456")
#=> "26c89ed68512269d003d32811bbd4527"

Replying to SMS via Twilio API with Ruby on Rails 4.0

I'm having a tough time understanding Twilio. I've read the docs many many times and still couldn't get my app run. I'm writing a web app in Ruby on Rails (4.0) to get an SMS text from students and print them out on the website.
In the Gemfile I put
gem 'twilio-ruby'
Then I have a controller like this
class TwilioController < ApplicationController
def index
end
def sent_sms
account_sid = "I put my ID here"
auth_token = "I put my auth token here"
twilio_phone_number = "xxxxxxxxx"
message_body = params["Body"]
from_number = params["From"]
#client = Twilio::REST::Client.new(account_sid, auth_token)
#client.account.sms.messages.create(
from: "+1#{twilio_phone_number}",
to: "+1#{from_number}",
body: "Hey there! I got a text from you"
)
end
Now I don't know how to print out those messages gotten from students to the webpage. I spent 2 days on this and still can't figure it out. Also, I don't know what to put in the URL in Twilio account in this screenshot below. I deploy my app to Heroku though. Any advice is appreciated.
https://www.dropbox.com/s/zxbyw6j5te8ipgp/Screen%20Shot%202014-04-12%20at%203.43.18%20PM.png
Twilio evangelist here.
Let me start clarify whats your trying to do. From the code above it looks like you want to receive a text message from your students and then send them back a simple response. You also want to print out the text messages that you've received? Hopefully I've got that right. If I do, lets start with receiving messages and sending a reply.
When a student sends a text message to your Twilio phone number, Twilio will receive that message and make an HTTP request to whatever URL you have set in the Messaging URL. Based on the Rails code in your post, it looks like that URL is going to be something like:
http://[yourdomain].com/Twilio/send_sms
Now, if you want to send a SMS message the student who sent you a message, you just need to generate and return some TwiML containing the <Message> verb from the send_sms function. That would look something like this:
twiml = Twilio::TwiML::Response.new do |r|
r.Message "Hey there! I got a text from you."
end
twiml.text
If you loaded the send_sms route in a browser you should see that your Rails app outputs some TwiML that looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Message>Hey there! I got a text from you.</Message>
</Response>
This code came from the "Replying to an SMS" quickstart which has a ton of great info in it. Another great resource for getting started with receiving text messages using Rails is this fantastic blog post.
OK, so now you've had a bunch of students send some text messages to you and you want to create a page in your Rails app to display them. For this you're going to need to use the REST API. This sample from the docs shows how to use the Ruby helper library to get a list of messages from Twilio. You can pass the list you get back from Twilio to your Rails view where you can loop over it outputting whatever HTML elements you want to use to display the SMS attributes.
Hop that helps.

Generate XML dynamically and post it to a web service in Rails

I am currently developing a Rails app in which I need to dynamically send XML request to an external web service. I've never done this before and I a bit lost.
More precisely I need to send requests to my logistic partner when the status of an order is updated. For instance when an order is confirmed I need to send data such as the customer's address, the pickup address, etc...
I intended to use the XML builder to dynamically generate the request and Net:HTTP or HTTParty to post the request, based on this example.
Is that the right way to do so? How can I generate the XML request outside the controller and then use it in HTTParty or Net:HTTP?
Thanks for your help,
Clem
That method will work just fine.
As for how to get the XML where you need it, just pass it around like any other data. You can use the Builder representation, which will automatically convert to a String as appropriate, or you can pass around a stringified (to_s) version of the Builder object.
If, for example, it makes sense for your model (which we'll call OrderStatus) to generate the XML, and for your controller to post the request:
# Model (order_status.rb)
def to_xml
xml = Builder::XmlMarkup.new
... # Your code here
xml
end
# Controller (order_statuses_controller.rb)
def some_method
#order_status = OrderStatus.find(:some_criteria)
... # Your code here
http = Net::HTTP.new("www.thewebservicedomain.com")
response = http.post("/some/path/here", #order_status.to_xml)
end
You may want to wrap the HTTP calls in a begin/rescue/end block and do something with the response, but otherwise it's all pretty straightforward and simple.
Make XML with Builder, then send it down the wire.
In your case it sounds like you may need to send several different requests as the order evolves; in that case:
Plan out what your possible order states are.
Determine what data needs to be sent for each state.
Decide how to represent that state within your models, so you can send the appropriate request when the state changes.
Where my example uses one method to generate XML, maybe you'll want 5 methods to handle 5 possible order states.

Rails 3 and Twilio to do phone verification

I am building an app in Rails 3, using twilio to verify a businesses existance. Basically, when you create a new buisiness I randomly generate a 6 digit number and then call the business phone number with this verification code and the user needs to enter it back in the system to finish the signup process. I am having trouble finding any relevant examples as to how to get this set up. I've found this, but it seems horribly outdated and doesn't work with Rails 3 seemingly. The documentation for the twilio-rb gem is confusing as well.
Does anyone know of any examples or have any code samples that could point me in the right direction?
As I said in the comment on your question itself, I am the author of the twilio-rb gem you mention. Off the top of my head, I would implement a verifications resource that you post a telephone number to.
POST /verifications.voice { telephone_number: '+12125551234' }
In the create action use Twilio::Call.create to create a new call with Twilio
def create
#verification = Verification.new params[:verification]
if #verification.save
Twilio::Call.create to: #verification.telephone_number,
from: YOUR_CALLER_ID, url: verification_url(#verification, format: :voice)
# 201 created and return verification code etc
else
# Handle errors
end
end
You will also want to rescue any API errors that twilio-rb might raise. The url refers to the show action of the verification resource instance. Twilio will then dial the supplied telephone number, and when the call is connected will request the url, e.g. GET /verifications/1.voice so you'll need a show view that asks for the verification code and collects the digits with the <Gather> verb:
res.gather num_digits: 4, action: twilio_hack_verification_url(#verification, :format => :voice), method: 'POST' do |form|
form.say 'Please enter the your 4 digit verification code'
end
Since Twilio currently does not implement the PUT verb, you'll to add a member to your resource
resources :verifications do
member { post 'twilio_hack' }
end
Then in your controller update the object with the user input:
def twilio_hack
#verification = Verification.find(params[:id]).tap do |v|
v.user_input params['Digits']
v.save
end
if #verification.confirmed?
# handle success
else
# handle failure
end
end
Finally in your model you'll need code that generates the verification code, and verifies if it is confirmed
class Verification < ActiveRecord::Base
before_save -> { self[:confirmed] = true if user_input == verification_code }, if: user_input
before_create -> { self[:verification_code] = rand.to_s[2..5] }
end
This is all untested and off the top of my head with about 2 minutes thought, but it should get you started.
When you wish to verify a Business:
Generate a verification code.
Use the Twilio REST API to initiate an outbound call, passing a URL for a callback to a controller which will handle the verification logic. Docs at Twilio are here and an example is here.
This means that you need to pass the verification code into your controller via the callback URL. Use a non-resourceful route with a bound parameter. See here.
Write a controller that handles the call and processes the verification:
Emit TwiML that challenges the user to enter the verification code. I have found using Nokogiri to build the TwiML myself to be the most straightforward approach. (See the method phone_greeting in this simple app I wrote: here.)
If it's correct, flag the Business as verified, congratulate the user, and hang up.
If not, loop.
Hopefully that's enough information to point you in the right direction.
Have you considered using Twilio's Outgoing Caller IDs to help solve this problem?
When calling Twilio over REST to add a new caller id to your account, Twilio will return a 6 digit verification code (property ValidationCode) for you to display in your UI, and then Twilio will automatically call the number and prompt for the code. When the user verifies the number over the phone, their number will be added to your account's caller ids. You can then query Twilio for their phone number over REST (parameter PhoneNumber) to ensure the verification was successful.
See here for documentation:
Add a caller id: http://www.twilio.com/docs/api/rest/outgoing-caller-ids#list-post
Find a caller id: http://www.twilio.com/docs/api/rest/outgoing-caller-ids#list

Rails TDD using a 3rd party mailer?

I have a rails application that I am implementing the Twilio SMS API on, and I am a bit lost on how to test drive my design.
To start I've just made a model that is an SMS mailer that will encapsulate the twilio API and I want to be able to test it and ensure functionality without using up SMS credits or bombarding someone with test text messages.
I know how to implement the API and get it working in the code but what I need help with is actually testing the code to make sure it works and prevent breakage in the future. Could anyone provide some advice?
Thanks!
You could use my gem Twilio.rb, which is already tested, and then mock it out in your tests, e.g. with mocha
Twilio::SMS.expects(:create).with :to => '+19175551234', :from => '+12125551234', :body => 'this is easy!'
Your unit tests should never hit external services, they should always be mocked. This is follows from a general principle of unit testing that tests should not extend the class boundary of the object being tested and collaborator objects should be mocked/stubbed.
Hope this helps!
https://github.com/stevegraham/twilio-rb
My experience with testing, and with testing Twilio applications, is that you test to eliminate risk you add. You'll want to use the Twilio gem rather than rolling your own SMS code against their REST endpoint: this minimizes the amount of risk.
Wrap the API as thinly as possible in your business logic class, and test primarily the business logic. For example, in my system, SMSes get sent out of the Reminder class. The code looks something like this:
class SomeWrapperClass
if (RAILS_ENV == "testing")
##sent_smses = []
cattr_accessor :sent_smses
end
def send_a_message(to, from, message, callback_url = nil)
unless RAILS_ENV == "testing"
Twilio::SMS.message(to, from, message, callback_url)
else
##sent_smses << {:to => to, :from => from, :message => message, :callback_url => callback_url}
end
end
end
This lets me write tests focusing on my business logic, which is the stuff I'm going to screw up. For example, if I want to test some method send_reminder(client) which sends a SMS message:
test "sends reminder to client" do
SomeWrapperClass.sent_smses = []
client = clients(:send_reminder_test_case)
Reminder.send_reminder(client)
sent_message = SomeWrapperClass.sent_smses.last
assert !sent_message.blank?, "Sending a reminder should fire an SMS to client."
assert sent_message.index(client.name) >= 0, "Sending a reminder should fire an SMS with the client's name in it.
...
end
Now I'm testing the actual risk I've added, which is that I'm screwing up Reminder.send_reminder. The wrapper, on the other hand, should be close to risk-free.
Obviously separate as much of the logic as possible. By doing this you can test everything else around as much as possible and then only leave the calls to the external API needing tests.
Working with external API's can be tricky. One option is to mock the response to something that you know will work for you or to the response you would expect, this can obviously be a bit brittle though. Another option is to look at something like VCR. This will record the call to the external API once and play it back again whenever you call it again.
This guy seems to have started solving your problem: https://github.com/arfrank/Fake-Twilio-Api
You probably don't need to test twiliolib's code, but if you don't want to stub twiliolib's methods you could use the FakeWeb gem, where you define the response for specified requests.
Similar to Steve mentioned, I just stub out the request with mocha:
# In Twilio initializer
TWILIO_ACCOUNT = Twilio::RestAccount.new(TWILIO_CONFIG[:sid], TWILIO_CONFIG[:token])
# In a test helper file somewhere
class ActiveSupport::TestCase
# Call this whenever you need to test twilio requests
def stub_twilio_requests
# Stub the actual request to Twilio
TWILIO_ACCOUNT.stubs(:request).returns(Net::HTTPSuccess.new(nil, nil, nil).tap { |n|
n.stubs(:body).returns("<?xml version=\"1.0\"?>\n<TwilioResponse></TwilioResponse>\n")
})
end
end

Resources