Caution!

This is an old post. Information here may be out-dated, or the post may re­flect opin­ions or be­liefs I no longer share.

Introduction

After tir­ing my­self out email­ing my ISP over and over for a re­fund, I de­cided to write a su­per sim­ple twit­ter­bot re­mind­ing @RCommCare at 8 a.m. every­day about the num­ber of days it has been since they have not sent me my re­fund. A fun lit­tle hour-long pro­ject, if you will.

This is the guide I wish I had when set­ting up my pro­ject, in­clud­ing both the pro­gram and how to de­ploy it on the server. It may or may not suit your use case. Keep in mind this is an ex­tremely sim­ple bot.

Folder struc­ture

Let’s go over our folder struc­ture:

- twitterbot          // Root folder
- config // Configuration folder
- client.rb // API keys
- schedule.rb // Schedule using 'whenever' gem
- .ruby-version // Ruby version for collaboration if required
- app.rb // Consumption of Twitter API
- Gemfile // Gems used
- Gemfile.lock // Lock file generated by Bundler
- README.md // Optional readme file

Set up our Ruby work en­vi­ron­ment

I am us­ing rbenv for man­ag­ing ruby ver­sions and will use Ruby 2.3.0 for the pro­ject. I have spec­i­fied my ruby ver­sion in a .ruby-version file as fol­lows. If you use a ver­sion con­trol sys­tem such as Git, you’d want to com­mitt this file.

2.3.0

Next, we need one of the Twitter API li­braries. Since we’re us­ing Ruby and are not con­cerned with the Streaming API, we can in­stall twit­ter by @sferik by spec­i­fy­ing it in our Gemfile:

source "https://rubygems.org"
gem "twitter"

Run bundle to in­stall the gem and its de­pen­den­cies.

Note that the twitter gem does not sup­port Ruby 2.4.

Get our Twitter API codes

Head over to Create Application page on Twitter (you must be logged in) and fill in the de­tails as re­quired on the form:

Create New Application page

Once you’ve cre­ated an app, head over to the Keys and Access Tokens’ tab and copy your Consumer keys.

Keys and Access Tokens tab - Consumer keys

Next, gen­er­ate an ac­cess to­ken from the same page and copy the two keys as well.

Keys and Access Tokens tab - Access Token keys

Write our ap­pli­ca­tion

We’re go­ing to store our se­cret API keys in en­vi­ron­ment vari­ables as op­posed to the config/client.rb file for se­cu­rity rea­sons. Twitter rec­om­mends against stor­ing the se­cret keys in hu­man-read­able form. Presuming you have shell ac­cess on the de­ploy­ment server, add the fol­low­ing to the /etc/environment file for per­ma­nently set­ting up the en­vi­ron­ment vari­ables.

TWITTERBOT_CONSUMER_SECRET="YOUR_CONSUMER_SECRET"
TWITTERBOT_ACCESS_TOKEN_SECRET="YOUR_ACCESS_TOKEN_SECRET"

The con­fig­u­ra­tion, then, will lie in config/client.rb as fol­lows:

require 'twitter'

CLIENT = Twitter::REST::Client.new do |config|
config.consumer_key = "YOUR_CONSUMER_KEY"
config.consumer_secret = TWITTERBOT_CONSUMER_SECRET
config.access_token = "YOUR_ACCESS_TOKEN"
config.access_token_secret = TWITTERBOT_ACCESS_TOKEN_SECRET
end

Next, we’ll sched­ule a cron­job us­ing the whenever gem. You can avoid us­ing a gem and sim­ply add a cron­job us­ing crontab util­ity us­ing your server’s shell, but for hu­man read­abil­ity and hav­ing the en­tire code at one place, I have cho­sen to use the afore­men­tioned gem.

We’re go­ing to in­clude it in our Gemfile and then bundle it:

source "https://rubygems.org"
gem "twitter"
gem "whenever", :require => false

Edit the config/schedule.rb file:

# Use this file to easily define all of your cron jobs.
# It's helpful, but not entirely necessary to understand cron before proceeding.
# http://en.wikipedia.org/wiki/Cron
# Learn more: http://github.com/javan/whenever

# Location for log file in case of errors
set :output, "~/.logs/cron_twitterbot.log"

# Deployed to MSK timezone
every 1.day, :at => '5:30 am' do
command 'username ruby ~/apps/twitterbot/app.rb'
end

Of course, re­place the username on line 11 with a user on your server who has ruby in­stalled. If you’re not con­cerned with ver­sion man­age­ment on the server, you can skip in­stalling rbenv or rvm and in­stall Ruby from your dis­tri­b­u­tion’s repos­i­to­ries:

sudo apt install ruby --yes

My ap­pli­ca­tion is pretty sim­ple. Here’s the app.rb file.

require_relative 'config/client'
require 'date'

def days_since_cancellation
start_date = Date.new(2017,02,06)
current_date = Date.today
return (current_date-start_date).to_i
end

CLIENT.update("Broadband cancelled on 02/06/17. Waiting for ₹302.41 refund since #{days_since_cancellation} days. Company policy 45-60 days. @RCommCare #CustomerService #Pathetic")

Deploy

Upload your twitterbot folder to your server via sftp or rsync. More on us­ing those two here.

On your server shell, cd to your twitterbot folder, pass the sched­ule file to when­ever, and let it up­date your user’s crontab:

whenever --load-file config/schedule.rb
whenever --update-crontab

You can check the crontab equiv­a­lent of your sched­ule by run­ning be­fore com­mit­ting it to the crontab file.

whenever --crontab-command

Key to note is that the user who is go­ing to run the pro­gram must have ac­cess to Ruby bi­na­ries (via a ruby ver­sion man­ager or with­out) and the same user must be logged in when run­ning whenever com­mands.