Send SMS messages like emails in Rails with Textris

September 12, 2016
Written by
Phil Nash
Twilion

The Twilio Ruby helper library makes sending SMS messages with Ruby really easy. In fact, it’s as simple as:

require "twilio-ruby"
client = Twilio::REST::Client.new(ENV["TWILIO_ACCOUNT_SID"], ENV["TWILIO_AUTH_TOKEN"])
client.messages.create(:from => A_TWILIO_NUMBER, :to => A_PHONE_NUMBER, :body => "Howdy")

But in the context of a web application this just isn’t very “Rails” is it? Are we mixing views and controllers? Where’s the separation of concerns? What about localisation?

If you’ve thought this, or even if you’re just interested in better ways to send SMS messages in your Rails application, then the Textris gem may be for you. It makes working with SMS messages as easy as working with emails using Action Mailer.

Let’s take a look at what it can do.

Working with Textris

We’re going to take an example Rails application and replace the existing message sending code with Textris to see how it can tidy up our application. For this blog post, we’ll use a tutorial on sending instant lead alerts as our base. The application is a landing page for real estate. When a user expresses interest in a house, the real estate agent is instantly alerted about it via SMS. This application is written using Rails 4, but Textris works just as well with the latest Rails 5 too.

To hack on the app along with this post, you’ll need a few things:

Now, clone or download the application repo from GitHub and follow the instructions in the README to get the app set up. Use your own mobile number as the AGENT_NUMBER so you will get the alerts. Once it’s setup you will see a page like this:

A screenshot of the application. It shows a house, a description and a form to fill in for more information.

Fill in some details in the form and submit. You will receive a message alerting you about the request with all the details you entered. Pretty sweet right.

When you fill in the form from the last image, you will receive a text message with the details from the form.

Let’s take this app and see what it would look like using Textris.

Setting up Textris

If you take a look around the application you’ll see that the NotificationsController (app/controllers/notifications_controller.rb) is where interested parties submit their details and where we send the SMS to the real estate agent. That uses a class called MessageSender (lib/message_sender.rb) which creates a Twilio::REST::Client and sends the message.

To change this, we first need to install Textris. Open up the Gemfile and add this line:


# Gemfile
gem 'twilio-ruby'
gem 'textris'

Install this by running bundle install on the command line in the project.

For Textris we need to configure Twilio ahead of time. Create a file at config/initializers/twilio.rb and add the following code:

# config/initializers/twilio.rb
Twilio.configure do |config|
  config.account_sid = ENV["TWILIO_ACCOUNT_SID"]
  config.auth_token  = ENV["TWILIO_AUTH_TOKEN"]
end

The final part of setting up Textris is to configure it to use Twilio for sending messages. Open up config/environments/development.rb and at the bottom of the block add:


# config/environments/development.rb
  # Raises error for missing translations
  # config.action_view.raise_on_missing_translations = true

  config.textris_delivery_method = :twilio
end

Textris has a number of delivery methods. Once you have this working in development with Twilio, you might want to switch this to :log so that you can see SMS messages in your Rails log instead of sending them whilst you are developing the app. Don’t forget to set the delivery method to :twilio in config/environments/production.rb before you deploy.

Creating a Texter class

Now that we have Textris set up in our app we can start to work with it. Textris behaves like Action Mailer. Just like how we create a  Mailer class to send emails with Action Mailer we need to create a Texter class to send SMS messages with Textris.

Create the folder app/texters and the file app/texters/agent_texter.rb. Enter the following code in your new file.

# app/texters/agent_texter.rb
class AgentTexter < Textris::Base
  default :from => ENV["TWILIO_NUMBER"]

  def alert(params)
    @params = params
    text :to => ENV["AGENT_NUMBER"]
  end
end

Like in Action Mailer, we can set default options for our SMS messages. In this case we set a default from number, our Twilio number.

Then we create a method that builds a message to be sent. The method returns a Textris::Message object that we create with the method text and the remaining options, in this case the number we are sending the message to.

Now we need a view to render when we send this message. Like other views in Rails, the template will have access to instance variables defined in the alert method. Create a directory for our AgentTexter‘s views at app/views/agent_texter and then create the file app/views/agent_texter/alert.text.erb. We can take the message template from the NotificationsController class and convert it to ERB.

<%# app/views/agent_texter/alert.text.erb %>
New lead received for <%= @params[:house_title] %>. Call <%= @params[:name] %> at <%= @params[:phone] %>. Message: <%= @params[:message] %>

Now that we have our Texter class and view in place we can remove the MessageSender and use our AgentTexter instead.

Using the AgentTexter

Open up the NotificationsController and start by removing the private method message. Now we can replace the line that uses the MessageSender class with our AgentTexter like so:

# app/controllers/notifications_controller.rb
 class NotificationsController < ApplicationController
   def create
-    MessageSender.send_message(message)
+    AgentTexter.alert(params).deliver
     redirect_to root_url,
       success: 'Thanks! An agent will be contacting you shortly.'
   rescue Twilio::REST::RequestError => error
     redirect_to root_url,
       error: 'Oops! There was an error. Please try again.'
   end
-
-  private
-
-  def message
-    "New lead received for #{params[:house_title]}. " 
-    "Call #{params[:name]} at #{params[:phone]}. " 
-    "Message: #{params[:message]}"
-  end
 end

We can delete the entire MessageSender class as well as its test file.

$ rm lib/message_sender.rb spec/lib/message_sender_spec.rb

Speaking of tests, we need to fix one up. The test for the NotificationsController expects the MessageSender class to receive a call to send_message. Instead, we can use Textris in test mode to test that we make one delivery when we submit the form. We clear the list of deliveries before each test so that deliveries in other tests won’t affect this one.

 # spec/controllers/notifications_controller_spec.rb
 require 'rails_helper'
 
 RSpec.describe NotificationsController do
   before(:each) do
     Textris::Base.deliveries.clear
   end
 
   describe '#index' do
     it 'send a notification' do
-      expect(MessageSender).to receive(:send_message).once
       post :create, message: 'message'
 
+      expect(Textris::Base.deliveries.count).to be(1)
       expect(response).to redirect_to(root_url)
     end
   end

Start up the application with rails server and navigate to localhost:3000. Enter a request to talk to an agent, hit the “Request info” button and celebrate as everything falls into place and you receive the text message. You can celebrate again when you realise that sending messages this way took 25 less lines of code!

You can check out my version of the newly Textris powered application on GitHub.

What’s next?

Now you’ve sent your first SMS message with Twilio using Textris there’s more features available to you that give you even more power.

  • You can take advantage of Active Job and process the API requests off the main thread by replacing the call to AgentTexter.alert(params).deliver to AgentTexter.alert(params).deliver_later. Check out how to setup Active Job in Rails with Sidekiq here.
  • If you hired more salespeople to sell your real estate, you could send lead alerts to all of them by providing an array of numbers to the AgentTexter‘s text method
  • Localise your SMS messages by adding templates for different languages, just like with other Rails templates. Textris renders to the locale set in I18n.locale

To see what else is available, check out the Textris documentation on GitHub.

I think Textris makes sending SMS messages in Rails feel natural and separates out views from controllers in a sensible way. What do you think? Let me know if you like the look of Textris or think you might use it in your next project. Or, do you know a better way of sending SMS messages in Rails? Drop me a line in the comments, by Twitter.