This is an old post. Information here may be out-dated, or the post may reĀ­ļ¬‚ect 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Ā­ļ¬ed my ruby verĀ­sion in a .ruby-version ļ¬le as folĀ­lows. If you use a verĀ­sion conĀ­trol sysĀ­tem such as Git, youā€™d want to comĀ­mitt this ļ¬le.

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 ļ¬ll 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 ļ¬le 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 ļ¬le 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Ā­ļ¬gĀ­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 ļ¬le:

# 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 ļ¬le.

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 ļ¬le 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 ļ¬le.

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.