How to Receive and Reply to an SMS in Rails with Twilio

April 19, 2016
Written by

twilio_on_rails2

This post was originally written by James Jelinek in 2016 and was updated by Ben White (bwhite@twilio.com) in April 2021. 

 


I’ve been working with Rails (and Twilio) for several years now and I love it. Twilio makes SMS, MMS, and Voice so easy to use. Even with the ease of use there is still somewhat of a learning curve as it pertains to integrating Twilio into your Ruby on Rails app. Today we’re going to cover a simple integration of Twilio into a new Ruby on Rails application that handles inbound and outbound messages. The first thing we need to do is to create a new Rails app.

rails new sms

This will generate our app simply called, “SMS”. Now we need to generate a basic controller to act as our endpoint for Twilio’s inbound requests.

rails g controller messages reply

When we create the controller we add a default method/action of reply  which will serve as our endpoint. The next step is to add the twilio-ruby  gem to our Gemfile .

gem 'twilio-ruby`

Now we need to bundle it into our app by running the following:

bundle install

Still with me? We are not far off! Now we need to configure the endpoint in config/routes.rb

resource :messages do
  collection do
    post 'reply'
  end
end

It should be noted that we can actually eliminate the resource block and simply use a post or match line in the config/routes.rb file, however, I anticipated the possible need of future functionality in the messages controller so I kept it as it. This will create a route that looks like http://localhost:3000/messages/reply which acts as the endpoint for Twilio to communicate with our Rails app. Now we need to setup our Twilio credentials and phone number in credentials.yml.enc .

Run rails credentials:edit to edit credentials.yml.enc. You'll want to include these values: 

twilio_sid: 'XXXXXXXXX'
twilio_token: 'XXXXXXXXXXXXX'
twilio_number: '+12125551212'

This will allow us to use the SID, auth token, and number later on in our controller. For security purposes, make sure that this file is not committed to version control / git. Now it’s time to get to the messages_controller and make this work.

To avoid CSRF errors and exceptions, we need to skip the verification of the authenticity token. If you are using Devise for authentication, you will want to also skip the authenticate_user!. This will allow Devise authentication inheritance but also allows calls to our reply method without passing credentials in the URL.

class MessagesController < ApplicationController 
  skip_before_action :verify_authenticity_token
 #skip_before_action :authenticate_user!, :only => "reply"

  def reply
    message_body = params["Body"]
    from_number = params["From"]
    boot_twilio
    sms = @client.messages.create(
      from: Rails.application.credentials.twilio_number,
      to: from_number,
      body: "Hello there, thanks for texting me. Your number is #{from_number}."
    )
    
  end

  private

  def boot_twilio
    account_sid = Rails.application.credentials.twilio_sid
    auth_token = Rails.application.credentials.twilio_token
    @client = Twilio::REST::Client.new account_sid, auth_token
  end
end

In our reply method which acts as the endpoint we need someway to grab the params that come in from Twilio’s request. So we instantiate message_body and from_number for further processing. We’ve created a private method called boot_twilio  which instantiates the Twilio client in preparation to send out a SMS message back to the user. In the reply method/action you’ll notice that after we boot_twilio we create a message that simply responds to the inbound phone number/request made by the end-user. For fun, we string interpolate from_number which sends back a simple message with the user’s phone number.

Twilio expects an HTTP response to its request, so we’ll render a snippet of XML with an empty <Response>. (Note from Greg: If all you wanted to do was reply to text messages, you could simply include the TwiML <Message>  tag in this XML response. But I dig James’ solution here because you can reuse his code to initiate text messages as well. There’s no one right way to do this.) 

Now this will not work without first setting up a publicly accessible webhook from Twilio back to the app. We need a way in our development environment to route traffic from the big scary Internet back to our private IP, because hey… none of us live in a datacenter. :)

To do this, we download ngrok and install/save the binary to our machine and move ngrok to your home directory. To start ngrok, open a terminal, navigate to the directory that has the ngrok binary, and run: 

./ngrok http 3000

This will generate a status screen and give us a url such as: http://08121ed87.ngrok.io . This is where the magic happens. Login to Twilio and go to Phone Numbers. Click on your phone number, then scroll down to the Messaging section and configure the Messaging Request URL with this:

http://yourngrokid.ngrok.io/messages/reply

Make sure the request type is set to HTTP POST and click save. Twilio is now properly configured.

Rails 6 added new middleware to prevent against DNS rebinding attacks. You'll need to clear the hostname allowlist in Rails by adding config.hosts.clear to /config/environments/development.rb. 

Now that we have our controller/endpoint and Twilio configured it’s time to test. Start your Rails server:

rails s

Send a text message to your Twilio phone number. Within a second or so you should see a response: “Hello there, thanks for texting me. Your number is +18323334444.”

If you receive this message, then pat yourself on the back. You now officially have Twilio integrated into Rails and are handling and replying to inbound messages. It should be noted that this is a very simple implementation intended to give you an idea on how to do a basic integration. Feel free to move the majority of the code out of the controller and into a class to follow Rails best practices.

Happy Coding! Now you know how to receive and reply to an SMS in Rails!

-James Jelinek (shakycode)


Thanks James! If you’d like to learn more about SMS and Rails, check out: