Tracking SMS conversation using Rails and Twilio - ruby-on-rails

I am using Twilio in my rails 3.1.3 app and I have got everything basically set up, i.e. a controller for sms and xml builders for the views depending on the response. The only thing I can't figure out is how to keep track of the conversation. The Twilio docs are pretty bad for using anything other than PHP to do this. I have tried using the Rails session hash, session[:variable], but it doesn't seem to be saving the session, as I tried redirecting and printing it out and got nothing. Below is the code of the controller.
def receive
# Check for session variable and redirect if necessary
#sms_state = session[:sms_state]
if #sms_state == 'confirmation'
redirect_to 'confirm'
end
if condition
#sms_state = 'confirmation'
session[:sms_state] = #sms_state
render :action => "view.xml.builder", :layout => false
else
#sms_state = 'new_state'
session[:sms_state] = #sms_state
render :action => "error.xml.builder", :layout => false
end
end
# method that should be called after user deals with first part
def confirm
if condition
#sms_state = session[:sms_state] = nil
render :action => "confirm_view.xml.builder", :layout => false
else
#sms_state = 'confirmation'
session[:sms_state] = #sms_state
render :action => "error.xml.builder", :layout => false
end
end
I have now set up a database table to track the current conversation state depending on the phone number contacting my app. The only thing now that I need to do is set an expiration for this conversation, just like a session or cookie. I am not sure how to do this or if its even possible.

This depends on how you define "conversation", but in general, you are better off using some sort of persistance (would recommend database over a file), and build the structure in accordance with your definition of a conversation.
Suppose the conversation is defined as text messages between two 10-digit phone numbers without a time limit, you can setup a db with a sender and recipient attributes, so if you need to output something in a user interface, you can look for sender and recipient phone numbers, and display all messages coming to them or going from them.
SMS is different from a phone call, since you can set cookies for the session of a phone call. SMS is done when either delivered or sent. When you receive an SMS to a phone number or short code, Twilio will make a request to the URL you provided for SMS, and your app can then respond. If you receive another response, it's a brand new request, so you have to construct the notion of "conversation".

Related

Twilio can't find xml on rails

I am integrating twilio click to call into my rails project.
Everything works fine however the url: in my twilio controller cannot be found on heroku. However, it can be found if you navigate to it in a browser. The phone dials but the voice says "Sorry a problem has occurred, good bye." If I change the url to an external xml file it works fine, just doesn't recognize this particular one. So I'm lead to believe that the controller etc works fine.
twillio_controller.rb
def call
#full_phone = current_user.phone
#partial_phone = #full_phone.last(-1)
#connected_number = "+61" + #partial_phone
#client = Twilio::REST::Client.new ##twilio_sid, ##twilio_token
# Connect an outbound call to the number submitted
#call = #client.calls.create(
:from => ##twilio_number,
:to => #connected_number,
:url => 'http://besttradies.herokuapp.com/mytradies/connect.xml', # Fetch instructions from this URL when the call connects
)
#msg = { :message => 'Phone call incoming!', :status => 'ok' }
end
def connect
# Our response to this request will be an XML document in the "TwiML"
# format. Our Ruby library provides a helper for generating one
# of these documents
response = Twilio::TwiML::Response.new do |r|
r.Say 'If this were a real click to call implementation, you would be connected to an agent at this point.', :voice => 'alice'
end
render text: response.text
end
The OP solved in the comments above:
Figured it out. Routes for connect needed to be POST and I also had to
add skip_before_action :verify_authenticity_token to the twilio
controller as it was behind membership doors.

what's the difference between send email with "deliver" and without "deliver"?

What's the difference between following two email invoke approach? One with deliver while another not.
mail(:to => 'test#gmail.com', :subject => "Test") do |format|
format.html { render layout: false }
end.deliver
mail(:to => 'test#gmail.com', :subject => "Test") do |format|
format.html { render layout: false }
end
.deliver actually send message, block without .deliver just create mail object but not send it. .deliver is operation for sending email like .deliver_later or custom created delivery method (example: you generate mail using method without .deliver and then your cron_job send this emails later).
You can find more information here:
http://guides.rubyonrails.org/action_mailer_basics.html#walkthrough-to-generating-a-mailer
or
good example working with emails:
http://railscasts.com/episodes/61-sending-email-revised?view=asciicast
As far as I can tell... just the flat mail function will send the email. If you construct a Mail::Message object, you need to call .deliver on it to get it to send, but the mail function seems to do that for you.
(At least, as far as I can tell. I have yet to test it, so I'm not sure)

How to call redirect_to in Delayed Job

I want to call redirect_to function in the Delayed job.
I have file print_job.rb
class PrintJob < Struct.new(:device,:survey,:filter_tags,:day1,:day2,:lastsurvey, :scale)
def perform
pc = PagesController.new
pc.redirect_to "http://google.com"
#pc.redirect_to :action => "print", :format => "pdf", :device => device, :survey => survey, :filter_tags => filter_tags,
#:day1 => day1, :day2 => day2, :lastsurvey => lastsurvey, :scale => scale
end
def success(job)
end
end
but it does not work. If I just put redirect_to "htpp://google.com". It said that no method redirect_to
The current situation now is I am using pdf kit with delayed_job but not exporting a pdf file directly. I have link locahost/print If i want to open it in format pdf, just put localhost/print.pdf or using link_to :action => "print", :format => "pdf" But if the pdf file is big, it does not have well performance so I want to open localhost/print.pdf in delayed_job. So how can I solve this problem
So how can I call redirect_to in delayed job now? Thank you!
delayed_job, are designed run long processes in background with out interrupting the http request of the rails controller. So it works like
1) controller gets a request
2) controller calls the delayed job and pass the 'long running'
process
3) controller move on without waiting for reply from delayed job
So in that context, what you asked is kind of 'strange', however , if your requirement is to notify the user, etc.. once the process is completed,
a) update a database column by the delayed_job and read it from your view
b) use some kind of a server-push method, its built-in to rails4, or using a gem like Faye
HTH
As mentioned above you could just use the database (one status column) and proceed that way (worker updates column, page some how auto refresh and get column values constantly) but right now at this time, i would highly recommend the use of active cable (which right now is part of rails 5+)
With active cable you can easily create a communication channel between your views or controllers and any worker, all you have to do is to setup a channel for your user and then send the messages from the worker while you already have a the listener (view with js code) that will get broadcast messages from the channel common channel (common between the view and worker using the same name/id etc this is really just a string representing the channel name, the js code (front end) will have it as well as the rails (back end) config)
Hope this helps!

Does the twilio-ruby gem handle SMS responses?

The only reference to SMS on the readme file is regarding sending SMS messages.
# send an sms
#client.account.sms.messages.create(
:from => '+14159341234',
:to => '+16105557069',
:body => 'Hey there!'
)
I'm wondering if the twilio-ruby gem provides visibility to SMS responses? I want to do some keyword response logic like the example they give here in PHP.
For others who may have this issue, I found this example application from this question to be very useful. What you need to do is:
Setup your Twilio Number SMS URL to Post to a certain controller in your application (e.g., myapp.com/twilio/process-sms)
Add a route to match that URL to the correct action in your Twilio controller
Write some simple logic like below to process responses/messages to your number according to your custom business logic
Respond, if necessary, using a .xml.erb file like the one below
class TwilioController < ApplicationController
def process_sms
#city = params[:FromCity].capitalize
#state = params[:FromState]
#from = params[:From]
u = User.find_by_phone_number(#from)
#user = u.name
b = params[:Body]
if b.downcase.include?("question")
#type = "Question"
#question = u.questions.build(:description => b)
#question.save!
render 'new_question.xml.erb', :content_type => 'text/xml'
elsif b.downcase.include?("contact")
#type = "Contact"
#contact = u.contacts.build(:name => b)
#contact.save!
render 'new_contact.xml.erb', :content_type => 'text/xml'
else
#type = "Not sure"
render 'not_sure.xml.erb', :content_type => 'text/xml'
end
The .build will create the object and the .save will save the object. Then you just return to Twilio the TWIML that you want to respond to the user. such as:
app/views/twilio/new_contact.xml.erb
<Response>
<Sms>We added a new contact for you.</Sms>
</Response>
When you get an SMS on your Twilio number, Twilio will make an HTTP request to your server. You can respond to the incoming SMS by responding to the request with XML, like this:
<Response>
<Sms>This is my response</Sms>
</Response>
You can either generate the XML response yourself, or the helper libraries contain methods that help you return XML to the client. I would suggest taking a look at the Twilio Ruby SMS quickstart for a simple example, and then going from there.

Ruby on Rails 3.0 Pusher Chat

I'm trying to implement something similar to http://pusher-chat.heroku.com/
However, I cannot figure out how to call an action without the page refreshing.
The page refreshing defeats the purpose of using pusher.
So far I have created a chat table, with attributes account_id and message.
In my chat controller I have the following:
def create
account = Account.getAccountById(session[:user])
if params[:message].blank?
#title = "Chat"
#chatLog = Chat.find(
:all,
:order => "created_at ASC",
:limit => 20
)
render :action => :index
else
chatter = Chat.new(
:account_id => account.id,
:message => params[:message]
)
payload = {
"account_id" => chatter.account_id,
"message" => chatter.message
}
if chatter.save
Pusher['chat-channel'].trigger('send_message', payload)
#title = "Chat"
#chatLog = Chat.find(
:all,
:order => "created_at ASC",
:limit => 20
)
render :action => :index
else
render :action => :index
end
end
rescue ActiveRecord::RecordNotFound
reset_session
redirect_to(new_account_path)
end
In my chat.js file I have the following:
$(document).ready(function() {
// Enable pusher logging - don't include this in production
Pusher.log = function(message) {
if (window.console && window.console.log) window.console.log(message);
};
// Flash fallback logging - don't include this in production
WEB_SOCKET_DEBUG = true;
var pusher = new Pusher('62651eca256339fa7fca');
var channel = pusher.subscribe('chat-channel');
channel.bind('send_message', function(chatter) {
$('#loading').show();
});
});
I've never built anything like this before, so I would appreciate any help.
I know there has to be a lot more javascript involved.
Thank you,
Brian
To call an action without refreshing you should use ajax.
I haven't tried pusher yet but it seems that whenever someone "submits" a new message, your application, it shall send to the pusher channel so it can broadcast to every "subscribed" client online.
If this is correct, you should think the whole thing as this:
When someone clicks on "new chat" it will create a new chat room, instantiate a new channel on pusher and save it on database. This will generate the identification on the url, that you can send to someone so that they can join your chat.
On the chat screen, you will have one big div that will render the chat and on input text field where you send messages. This particular field will submit to your application using ajax your chat ID and the message.
On your chat controller when you receive this information, you go get the pusher channel id on database for that chat room, save message on database for history and send it back to every user connected on that room with pusher.
The logic to render the text on the chat will be done by client side javascript.
Hmmh, my approach would be to use a Javascript timer which calls an AJAX-script every two seconds to get the new chat entries since the last request - and then refresh only the chatbox. Like so:
var latest_entry_number = 0;
var chatter = window.setInterval("getNewestEntries()",2000);
function getNewestEntries() {
$.ajax({
url: "/path/to/latest_entries",
type: "POST",
dataType: "JSON",
data: {latest_entry: latest_entry_number}
success: appendEntries
});
}
function appendEntries(data) {
latest_entry_number = data.latest_entry;
$.each(data.entries, function(key,val){
//append the entries to the chat
})
}
And the controller action would look like this:
def latest_entries
data[:latest_entry] = get_latest_entry # each entry gets a consecutive, ascending number
data[:entries] = get_entries_since(params[:latest_entry_number]) # get all entries done since that number
# Should be an array
render :json => data
end
Or something like that.

Resources