12 Hacks of Christmas – Day 8: Christmas Carol Lyrics by Text Message
Time to read: 5 minutes
My wife and I took our newborn daughter out shopping on Michigan Ave last weekend. Walking out of Macy’s, I saw a bunch of carolers holding sheets of paper with song lyrics. I thought, “Who has printers and copiers anymore?”
But most everyone’s got a cellphone these days. Maybe they don’t want to install an app. Maybe they don’t have a data plan. But most folks these days can get a text.
And so I spent last night building the Christmas Carol Lyric Line. If you’d like to see how it works, text “carols” to 907.312.1412.
I wrote this app using Ruby and Sinatra. It’s quite straight forward and below I’ll show you how I did it. Before we get to that though, I want to get something off my chest.
The finished code I’m about to walk you through is fairly clean and modular, but as you can see from the Github history, it didn’t start off that way. Lots of stuff hardcoded, lots of long methods and messy code. It feels a bit disingenuous to write a post saying, “Here’s how I would build this thing” when, in reality, they way I would build this thing is to throw together a bunch of ugly code until I got it working, then refactor to make it easier to maintain, easier to extend and easier to talk about.
With that said…
The idea was that someone could text in, get a menu of songs, reply back with their menu selection and get the lyrics for that song.
I decided to build a Sinatra app. I didn’t do a lot of Sinatra before starting at Twilio but it turns out Sinatra’s pretty useful for building quick Twilio apps, since it’s so stripped down — you can often fit all your code in a single file.
Well, almost one file. In my new project directory, I did create a Gemfile which included:
Then I created twilo.rb where the rest of the code in this post goes. I started it off by requiring Sinatra:
Getting the Lyrics
Next step was to get some song lyrics. That was pretty easy as there are 3.5MM results on Google for “Christmas carol lyrics.” I created a lyrics directory and dropped the songs in there, one text file per song.
On my first iteration I hardcoded the song menu. But then I wanted to add some songs and found it to be a pain in the ass to change the hardcoded menu every tine. So, I figured why not just automatically create the menu based off of the files in directory?
I renamed the files in such a way that it’d be easy to extract a pretty name — e.g, Away-In-A-Manger.txt instead of away-in-a-manger.txt. Then I wrote a method to do the transformation:
Then I needed a method that would get all the filenames in the lyrics directory, delete the system filenames that start with a period, and sort the rest in alphabetical order:
Then I used those two methods to create the text for a menu:
Once I had my menu to display when someone texted in, I needed to deal with their input. First step is to figure out the list of valid menu options (‘1’, ‘2’, etc.):
Then I needed to convert a valid menu option into a filename. For instance, the user replies with ‘1’ and I return the first filename from the directory array. You’ll notice that I subtracted one from whatever the user texted — muggles don’t do zero indexing:
Once I had a filename, I needed to pull the lyrics:
Alright! So now I have my output for each state: the user texted in a valid menu option (I return the lyrics) or the user texts in something else (I return the menu). Now I just needed to deal with the whole texting thing.
Texting the North Pole
First I did a quick Google search to find the area code for the North Pole. Very important.
Then I opened up my Twilio dashboard and searched for a number in the 907 area code (Fun fact, the North Pole and Anchorage share area codes):
And wouldn’t you know it, not only do we have North Pole area codes but we’ve got North Pole area code numbers that include 312 — the area code for Chicago! It really is Christmas.
I snagged that third phone number as it seemed easiest to remember. Then I set the messaging webhook to http://baugues.ngrok.com/messaging. (If you haven’t used ngrok before, you should. It lets you expose your local development server to the Internet. Makes development cycles a lot faster. Kevin Whinnery wrote about it here.)
When someone texts my Twilio number, Twilio’s makes a POST request to that URL and passes along information in the params, just like if someone submitted a form. The bit that I’m interested in, the message body, is found in params[‘Body’].
I wrote a route to handle the POST request:
The if statement checks if the body of the incoming text is included in the list of valid menu options. If it is, then we use the lyrics from the filename pulled from the files array. If it’s not, then we generate the menu.
Then I needed to convert that message into the the kind of specialized XML Twilio expects called TwiML.
And that’s it. I fired up Sinatra app by running ruby twilio.rb from the terminal. To make sure things were working right, I tested my webhook with Postman:
Then I sent off a text to my shiny new Twilio number, chose a song, and got my lyrics.
Putting a bow on it
Once I knew it was working, I needed to get it off my development machine. There are a hundred ways to deploy these days. Recently I’ve been deploying to my VPS on Digital Ocean using Dokku, which gives you Heroku-like deployments via Git. Here’s a great tutorial from Digital Ocean on using Ruby and Dokku together.
One thing you’ll read about in that tutorial is the necessity of a config.ru to tell your server what exactly it’s supposed to do with the repository you just gave it. In my case, I want it to include twilio.rb and start Sinatra. So I created a new config.ru and wrote:
Since I already had a git repo going, I just had to make sure everything was up to date, create a new Dokku instance and push it real good.
Last step was to update the webhook in my Twilio dashboard to the production URL.
And that’s it!
I’m trying to get the word out about the Christmas Carol Lyric Line so that people know about it as they go out to spread holiday cheer this weekend. Would you be up for retweeting this tweet or simply sharing the phone number: 907.312.1412.
Merry Christmas,
Greg B.
gb@twilio.com
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.