Last time I described how to integrate a Rails app with Facebook Connect, today I’d like to take a moment and give you a small tour on how to integrate it with Twitter OAuth.
In case you missed it, OAuth is a protocol for authorizing APIs without the need of supplying any passwords in our application – we just store the tokens we later use for interacting with the API. Ok, let’s get started.
One thing you’ll need is a Rails App – I’ll be using my usual Twitter-clone app called Statusr. I’d like the statuses from Statusr to be pushed to Twitter.
The first thing I’ll need is to register my application on Twitter. To do that, log in to Twitter and go to http://twitter.com/oauth_clients/new. Fill out the form and remember to specify the callback url - it should be the action that will handle the callback from Twitter. It must be a valid url, so http://localhost or http://localhost:3000 will not work. You need to set up a domain name on your machine to make it work (on Mac OS X you can use NetInfo). In my case it’s http://statusr.local/twitter/new. You can always change it later if you’re not sure now.
The Application Type should be set to Browser. Also, select Read & Write under Default Access type. I will not be covering logging with Twitter now, so leave that option empty. When you’re done, click save.
Congratulations, you have an app registered on Twitter! Note down the token and secret keys, and put them on the bottom of config/environment.rb, like this:
TWITTER_CONSUMER_KEY = 'YOUR_CONSUMER_KEY' TWITTER_CONSUMER_SECRET = 'YOUR_CONSUMER_SECRET'
Now it’s time to integrate our app.
We’ll be using moomerman-twitter_oauth gem, which will allow us to use the api in a simple manner
gem sources -a http://gems.github.com sudo gem install moomerman-twitter_oauth
Once we have it installed, we’ll start integrating out app.
We will have to prepare our User model to be able to handle the Twitter Api via OAuth. Let’s fire up a migration:
script/generate migration AddTwitterOAuthToUser
In it, put the following definitions:
class AddTwitterOAuthToUser < ActiveRecord::Migration
def self.up
add_column :users, :twitter_token, :string
add_column :users, :twitter_secret, :string
end
def self.down
remove_column :users, :twitter_token
remove_column :users, :twitter_secret
end
end
Afterwards, run the migration:
rake db:migrate
Ok, now let’s add some convienience methods to the User model:
class User < ActiveRecord::Base
#... previous code
# returns true if user has twitter tokens
def twitter?
self.twitter_token && self.twitter_secret
end
# holds the twitter client
attr_accessor :twitter_client
# returns an instance of TwitterOAuth::Client if user has twitter tokens
def twitter
if twitter?
return self.twitter_client if self.twitter_client
self.twitter_client = TwitterOAuth::Client.new(
:consumer_key => TWITTER_CONSUMER_KEY,
:consumer_secret => TWITTER_CONSUMER_SECRET,
:token => self.twitter_token,
:secret => self.twitter_secret
)
else
false
end
end
end
With these methods we can access the TwitterOAuth client for a specific user easily. User#twitter? will return a boolean status whether it is integrated or not and User#twitter will return a TwitterOAuth client.
Now we need handling of the authorization process. It will be done by a controller:
require 'twitter_oauth'
class TwittersController < ApplicationController
skip_before_filter :login_required
before_filter :link_client
def destroy
begin
current_user.twitter_token = nil
current_user.twitter_secret = nil
raise 'Could not save user' if !current_user.save
flash[:notice] = 'Your have revoked your Twitter account authorization'
rescue
flash[:error] = 'Could not revoke your Twitter account authorization'
end
redirect_to(edit_user_path(current_user))
end
# authorize oauth client and save access keys
def new
begin
if params[:oauth_token] != session['oauth_request_token_token']
flash[:error] = 'Could not authorize your Twitter account'
return redirect_to(edit_user_path(current_user))
end
oauth_token = session['oauth_request_token_token']
oauth_secret = session['oauth_request_token_secret']
# if we're here, save the tokens to user
access_token = @client.authorize(
oauth_token,
oauth_secret
)
if @client.authorized?
client_info = @client.info
current_user.twitter_token = access_token.token
current_user.twitter_secret = access_token.secret
raise 'Could not save user' if !current_user.save
end
session['oauth_request_token_token'] = nil
session['oauth_request_token_secret'] = nil
flash[:notice] = 'Your account has been authorized at Twitter'
rescue
flash[:error] = 'There was an error during processing the response from Twitter.'
end
redirect_to(edit_user_path(current_user))
end
# start a request and send to twitter
def create
request_token = @client.request_token
session['oauth_request_token_token'] = request_token.token
session['oauth_request_token_secret'] = request_token.secret
redirect_to request_token.authorize_url
end
private
def link_client
@client = TwitterOAuth::Client.new(
:consumer_key => TWITTER_CONSUMER_KEY,
:consumer_secret => TWITTER_CONSUMER_SECRET
)
end
end
Remember to put this in config/routes.rb:
map.resource :twitter
The controller uses 3 REST methods – new, create and destroy. Create is used to get a request token from Twitter and redirect to a page on twitter.com where the User authorizes our app. New handles the callback from twitter, authorizes the client and saves the access keys. Destroy removes the keys from the User essentially disabling the OAuth client.
To let the user authorize, we need to add links to one of the pages. In my example, I put this in users/edit.html.erb:
<h1>Twitter</h1> <% if current_user.twitter? %> Twitter authorized! - <%= link_to 'click here to deauthorize Twitter', twitter_path, :method => :delete %> <% else %> <%= link_to 'Authorize Twitter', twitter_path, :method => :post %> <% end %>
At this point, when you go to users/:id/edit, and click on ‘Authorize Twitter’, you are redirected to Twitter, where you allow (or deny) the application access. If you allow, you are redirected back to the app, which saves your access token and secret and displays a flash message informing you that ‘Your account has been authorized at Twitter’ (that is if nothing went wrong along the way).
At this point we have an authorization mechanism for Twitter OAuth and a client associated to a specific user. So far we’ve been working on authorization – now it’s time to do something fun! Let’s push statuses from Statusr to Twitter. This example will also show how easy it is to interact with the Twitter API via OAuth.
In StatusesController#create, I’ll add the following line right after the status is saved:
current_user.twitter.update(@status.status) if current_user.twitter?
Now let’s try to add a status in Statusr:

Screenshot of Statusr with a status which should go to Twitter
Ok, status added, but has it been sent to Twitter? I’ve authorized my development account so it should be visible there…
And it is! The great thing about OAuth is how easy it is to work with the API once the authorization is done. Also, you don’t need to store any passwords which is also great for users. I hope you liked this tutorial! I’ve also included the source code for Statusr – you can download it here.



Interesting post, but why not using the twitter Auth gem? (http://github.com/mbleigh/twitter-auth/tree/master), it makes everything much easier no?
Thanks a lot for the response. That gem looks great – I missed it, but I’ll give it a spin soon!
As for the tutorial, I wanted to go through the whole process in case someone wanted to find out how the oauth works and have more control (like introducing custom callbacks).
I’m always wondering why:
—
# returns true if user has twitter tokens
def twitter?
if self.twitter_token && self.twitter_secret
true
else
false
end
end
—
and not simply:
—
def twitter?
self.twitter_token && self.twitter_secret
end
—
not sure why, but a good catch
I’ve edited the example as it is more elegant. Thanks!
Keep up the good writing
Really interesting article. Thank you for moving along the time with a great read.
I’m trying out ur example..but when i go to twitter.com i’m not getting redirected to my app. Instead a message displayed on twitter :
“You’ve successfully granted access to iphonepurpletrail!
Simply return to iphonepurpletrail and enter the following PIN to complete the process.
5420096″
My apps callback url is “http://iphone.girish.com/twitter/new” i.e. “http://localhost/twitter/new”.
thanks for ur help!!!!