Joshua Blewitt

Using the Twitter API on Ruby with a Ruby Gem!

So recently I've been expanding on my Ruby knowledge and there are two areas I've been wanting to focus on.

  • Gems
  • Making HTTP Requests

And today, I'll be (partially) achieving both of those goals today, as this post will be about calling the Twitter API using a Ruby Gem! 🎉

So, after my Twitter developer account got approved (I still think that writing at least 200 words just to get approved is silly), I created my application, generated my keys and got to work researching ways to make HTTP requests in Ruby. My research initially lead me to the documentation for NET:HTTP. But sadly, calling the Twitter API was going to be a bit more complex then I originally thought. I needed to create a client that used the API keys generated on my application on Twitter's devleoper site.

After doing more research into using Ruby to call the Twitter API specifically, I discovered a Ruby Gem called twitter. After looking at the documentation, this seemed like the perfect solution!

Of course, the code for this project can be found here. (Note: you may notice that the keys are missing from the solution, you'll need to add your own if you want the application to work!)

So, let's get to work.

First things first, lets import the twitter ruby gem.

#require specific gems
require 'twitter'

And then configure our client with our API keys from Twitter:

#configuring twitter api
client = Twitter::REST::Client.new do |config|
config.consumer_key = ''
config.consumer_secret = ''
end

Let's make a working proof of concept first, just to make sure that the client has been configured properly.

puts "\nLet's take a look at some recent tweets from a user!"
tweets = client.user_timeline('_ItsJayB_', count: 10)
puts tweets

Cool, so this should print the last 10 tweets from my twitter account!

Right?

Let's take a look at some recent tweets from a user!
#<Twitter::Tweet:0x0000000006697458>
#<Twitter::Tweet:0x0000000006697430>
#<Twitter::Tweet:0x0000000006697408>
#<Twitter::Tweet:0x00000000066973e0>
#<Twitter::Tweet:0x00000000066973b8>
#<Twitter::Tweet:0x0000000006697390>
#<Twitter::Tweet:0x0000000006697368>
#<Twitter::Tweet:0x0000000006697340>
#<Twitter::Tweet:0x0000000006697318>
#<Twitter::Tweet:0x00000000066972f0>

Well, that doesn't look right. At least it's pulling data though!

But why is it displaying a key value pair and not the actual context of each tweet? 🐱‍💻

Well, we need to look at the methods included with this gem. More specifically, the 'each' method.

So after looking into the 'tweet' identity in the documentation (and for 'full_text') and some research online, we need to iterate through each tweet.

Like so:

tweets.each { |tweet| puts tweet.full_text }

Which would then give us...

Let's take a look at some recent tweets from a user!
RT @ColorPrinter_: Jeff Gerstmann tells you you're wrong for 22 seconds https://t.co/PBE7SO8ehO
RT @BBCArchive: #OnThisDay 1995: Windows 95 was released. https://t.co/AZWcK9p40Y
Been spending some time developing a small currency conversion application. Now, I've reworked it to call an API! F… https://t.co/7sHCIUL9aI
Glad that the @harrys code from the @CAGcast worked in the UK! Thanks @CheapyD, @NewWombat and @Shipwreck! �👏
Pretty amazed that I've made my own website - and hosted it too! �👏 https://t.co/CpUEzLatyr
Hey @UNIQLO_UK - are there any plans to open a store in Milton Keynes? �🤔
@polymegaHQ Thanks! �👏
Any updates on this @polymegaHQ ? https://t.co/uCTlXJUEMY
I've gone live On Twitch and Mixer with @MTG_Arena - come hang out! The London Mulligan!
https://t.co/ROpqyHWJSU… https://t.co/pEB0UE472s
@mashd @Twitch @wizards_magic @MTG_Arena That’s Magic!

Great - we're getting somewhere!

Viewing tweets for a user is great and all, but what about seeing tweets using a specific phrase being sent to the account from other twitter users?

Well, turns out - there's something for that too.

client.search("to:#{twitterAccount} #{phrase}", :count => 1, :result_type => "recent").take(5).each do |tweet|
puts tweet.text

So, we specify the account and the phrase. Then, using 'count' we state how many tweets per page we want to display (the max value is 100), then state what type of search results we want with 'result_type' (set to recent) and finally, we have a take method. The take method returns a specified number of elements (or tweets in this case) from an array. In this case, for each tweet it finds, it prints it to the screen.

Here's an example of what we would see in the console:

@NintendoUK Nope! But I can’t wait to finally play through a classic Zelda game that I have somehow missed over the… https://t.co/32ynOfpkGh
@NintendoUK I cannot wait 3 days away untill this game comes out for the switch looks amazing I will be behind my Z… https://t.co/nArzhmn3Eh
@NintendoUK If only there was something to speed the time up with Zelda links 
awekening
@NintendoUK Tbh, zelda BOTW was my favourite game on the switch, wonder if this will take its place? �🤔
@NintendoUK Isn’t there a song of Times or something like that from zelda. ��
https://t.co/yhhSvQaWJI

Finally, we move onto something that I wanted to try and do - streaming tweets in real time.

Thankfully, there was some documetation for streaming tweets using the Ruby Gem.

First of all, we need to create a new client. This client however will be a Streaming client as opposed to a REST client

client = Twitter::Streaming::Client.new do |config|
        config.consumer_key        = ''
        config.consumer_secret     = ''
        config.access_token        = ''
        config.access_token_secret = ''
        end

After we have a client, let's pick a topic and stream in relation to the specified topic

puts "Please enter a topic you wish to stream tweets about. Please note that this will stream tweets in real time!"
#get user choice for topic
topic = gets.chomp
client.filter(track: topic) do |object|
puts object.text if object.is_a?(Twitter::Tweet)
end

So after the user states what topic they want to see tweets for, this is passed to the track options hash which is part of the filter class. Then it prints to the screen every tweet it finds.

Alright, lets put all this into an application which somebody could use!

First, let's define a class which will store all the methods we need for this. (I'll update my C# currency application with classes and methods I promise!)

#require specific gems
require 'twitter'

#define class - remember, the class name should always start with a capital letter
class TwitterConfig
    #attribute reader
    attr_reader :twitterAccount
    #initialise class - used for configuring 
    def initialize (twitterAccount)
        @twitterAccount = twitterAccount
    end
    
    public
    def printName
        #confirming the name of the twitter account set to
        puts "Account set to - #{twitterAccount}"
    end

    public
    def viewTweets
        puts "How many tweets from the user - #{twitterAccount} - do you want to view?"
        number = gets.chomp
        #configuring twitter config
        client = Twitter::REST::Client.new do |config|
        config.consumer_key = ''
        config.consumer_secret = ''
        end
        puts "\nLet's take a look at some recent tweets from a user!"
        #uses the user_timeline method to find the account, count is returning the number of tweets
        tweets = client.user_timeline(twitterAccount, count: number)
        tweets.each { |tweet| puts tweet.full_text }
    end

    public
    def phraseTweets
        puts "Please enter the phrase you want to see tweets for from users!"
        phrase = gets.chomp
        puts "How many tweets do you want to see?"
        num = gets.chomp.to_i
        #configuring twitter config
        client = Twitter::REST::Client.new do |config|
        config.consumer_key = ''
        config.consumer_secret = ''
        end
        #searching tweets from a user with a specific phrase most recent displayed
        #for each tweet it finds, display it to the screen
        #count is returning the number of tweets per page - max is 100
        #result type specifies what type of search results you want
        #the take method returns specified number of elements (tweets in this case) from an array
        #And finally, there is an each method to print every tweet it finds
        client.search("to:#{twitterAccount} #{phrase}", :count => 1, :result_type => "recent").take(num).each do |tweet|
        puts tweet.text
        end
    end

    public
    def streamTweets
        #configuring a new streaming client with relevant keys
        client = Twitter::Streaming::Client.new do |config|
        config.consumer_key        = ''
        config.consumer_secret     = ''
        config.access_token        = ''
        config.access_token_secret = ''
        end
        puts "Please enter a topic you wish to stream tweets about. Please note that this will stream tweets in real time!"
        #get user choice for topic
        topic = gets.chomp
        #for every tweet it finds, print to the screen
        #pass the topic variable to the track options hash (part of the filter method)
        client.filter(track: topic) do |object|
        #prints the tweet if the object is a tweet (from the Twitter class)
        puts object.text if object.is_a?(Twitter::Tweet)
        end
    end
end

Okay good, we've got public methods so they can be accessed outside of the class.

Now let's make an instance of this class.

puts "Welcome to Twitter on Ruby!"
puts "Please state the twitter user name you wish to view tweets for. Make sure that the account name is correct!"
userName = gets.chomp
#creates a new instance of the TwitterConfig class
twitterSet = TwitterConfig.new(userName)
#calls the method to print the username the user chose
twitterSet.printName

So after we declare a new instance of the class, I call the method 'printName' - just to make sure that the username was set.

So, once again - it's time to do another while loop with a boolean variable...

#boolean declared - set to true
check = true

#while loop to ensure that the program loops.
while check == true
    puts "Please pick a menu choice by typing the letter in brackets!"
    puts "(V)iew tweets from a user"
    puts "(F)ind tweets with a specific phrase"
    puts "(S)tream Tweets"
    puts "(Q)uit"
    #get user choice and convert it to upper case
    userChoice = gets.chomp.upcase
    case userChoice
    when 'V'
        twitterSet.viewTweets
    when 'F'
        twitterSet.phraseTweets
    when 'S'
        twitterSet.streamTweets
    when 'Q'
        puts "Quit"
        #sets the boolean value to false and exits the program
        check = false
    #if a user enters a command that isn't valid - run this!
    else
        puts "Invalid command - try again!"
    end
end

So inside the while loop (while the boolean is true), there is a case statement which will run a method depending on which key is pressed. The character is converted to uppercase as well so if the user enters a lowercase 'v' for example, the choice for 'V' will be hit. The 'else' statement is there to catch any other character the user inputs.

It's interesting streaming tweets to the console in real time and it was a fun challenge to tackle. Plus, I got experience with researching gems and reading documentation to solve the problem. I plan to recreate my C# program using NET:HTTP so I can become more confident with performing HTTP requests to API's.

I plan to come back to this in the future so I can additional functionality, such as writing tweets to a file.

Thanks for reading!

Tags:


A photo of me!

I'm Joshua Blewitt, I'm passionate about product, a technology advocate, customer champion, curious mind and writer. I've worked for companies such as Rightmove, Domino's Pizza and IQVIA.

Let me know your thoughts!
More about me