2009年12月19日
新しいブログで記事を見る。
最近モーニングツイートいうTwitter連携サービスを作ってます。
その備考録も兼ねて。

一応動作環境も。
OS:Mac OS X 10.6.2
Ruby:1.8.7
Rails:2.3.5
RubyとRailsがインストールされてる前提で話を進めます。
最後にライブラリの説明や僕が参考にさせて頂いた記事へのリンクをまとめておきますのでそれをご参照ください。
その備考録も兼ねて。

一応動作環境も。
OS:Mac OS X 10.6.2
Ruby:1.8.7
Rails:2.3.5
RubyとRailsがインストールされてる前提で話を進めます。
最後にライブラリの説明や僕が参考にさせて頂いた記事へのリンクをまとめておきますのでそれをご参照ください。
ライブラリのインストールとプロジェクトの作成。
まずはRubytterとOAuthをインストール。
適当なフォルダにRailsプロジェクト作成。
名前は取りあえず『twitter』にしておきましょう。
プロジェクトに移動して、コントローラの作成。
index→認証ボタン表示 / ツイートの表示
oauth→認証ボタンを押した時にTwitterに転送する
callback→Twitterから戻ってきた時の後処理
TwitterへのConsumer登録。
これからアクションとテンプレートをガリガリ書いていきます。
と、その前に、大事な事を忘れていました。
OAuth経由でTwitterにアクセスする場合、コンシューマ登録が必要となります。
http://twitter.com/oauth_clients

こちらから登録して、Consumer KeyとConsumer Secretを取得してください。
途中アプリケーションWebサイトとコールバックのURLを入力する欄がありますが、適当なURLでOKです。僕は『http://example.com』と入れました。
準備は出来ましたか?では次に進みましょう。ლ(╹◡╹ლ)
サンプル作成。
親コントローラにRubytterとOAuthのロードと、クラスメソッドを追加。
Consumer KeyとConsumer Secretは自分で取得した物に置き換えてください。
/app/controllers/application_controller.rb
まずはTwitterの認証に飛ぶためのボタンを設置。indexコントローラは空のままで良いので、テンプレートを書きましょう。
/app/views/index/index.html.erb
ひとまずここでサーバーを動かしてみましょうか。
プロジェクトのルートで以下のコマンド。
ブラウザで『http://localhost:3000/』にアクセス。あれ?Welcomeページが表示されました。

気を取り直して、Welcomeページ(/public/index.html)を削除。
ルートでindexコントローラーが使えるように、ルーティングも変えましょう。
/config/route.rb
ブラウザに戻ってページをリロード。

ちょっと寂しいですが、自分の作ったものが表示されました。
次はoauthアクションを書きましょう。『:oauth_callback』はコールバック先のURLを指定してください。今回は『callback』にしておきます。
/app/controllers/index_controller.rb
ここまで書いて再びブラウザに戻ります。
先程のボタンをクリック。Twitterに転送されます。『Allow』ボタンを押してコンシューマからのアクセスを許可してください。

ボタンを押すと、先程指定したコールバックURLに転送されます。
まだ何も書いてないので空ページが表示されます。

では、次に行きましょう。
/app/controllers/index_controller.rb
indexのテンプレートも編集。
/app/views/index/index.html.erb
再びアクセスしてみましょう。
indexのボタンクリック→Twitterに転送、『Allow』ボタンをクリック→戻ってくる。

おお!認証されました。
でも、これだけじゃ面白くないので、Twitterからつぶやきを持ってきましょう。
つぶやきを表示する。
indexコントローラのindexアクションを編集
/app/controllers/index_controller.rb
indexのテンプレートを再度編集。
/app/views/index/index.html.erb
ページをリロード。自分のタイムラインが表示されました。

まとめ。
全部で100行もないコードでこれだけの事が出来ました。
ライブラリ開発者様に感謝です。
というか、そもそも僕がこの記事を書いた目的。
僕は前々からTwitterのクライアントを作ってみたいと思っていました。たまたま目にしたRailsでTwitterのOAuthを試すの記事を見て、Ruby/Railsの勉強を兼ねて実際に作ってみました。作ってみたんですが、うまく動かないというか、期待してた動きと違ってたんです。どうやら僕が理解してた(と思ってた)OAuthの概念と実際のOAuthの動きに差異があったようです。で、半泣きになりながら色々な記事を参照したりサンプルを見たりして試行錯誤してました。その経緯を自分の備考録としてまとめるためと、また、僕と同じようにOAuthの概念がイマイチよく分からなくてハマる人がいるんじゃないか?と思って書きました。え?いないですか?そうですか。しかし、実際に手を動かして試したり、この記事を書くために色々な記事を参照することで、自分の理解を深めることが出来ました。ლ(╹◡╹ლ)
もし『この記事読んで余計分らなくなったぞこの野郎!』って人がいましたらコメントかTwitterにて優しく突っ込みを入れてください。ごめんなさい。
参考リンク。
ゼロから学ぶOAuth:第1回 OAuthとは?―OAuthの概念とOAuthでできること
OAuthの概念について。今読むととても理解出来るんですが、最初はよく分かりませんでした。実際に手を動かして作ってみるのが良いと思います。
Ruby OAuth GEM
RubyライブラリOAuthの公式サイト。
RailsでTwitterのOAuthを試す
RubyのライブラリOAuthの使い方。
今回書いた記事のほとんどはここを参考/引用させて頂いております。
jugyo's rubytter at master - GitHub
RubyライブラリRubytterのGithub。
Rubytter
RubyライブラリRubytterの使い方。ライブラリ作者様のブログ。
rubytter と oauth を使う
OAuthとRubytterの連携方法。
まずはRubytterとOAuthをインストール。
$ sudo gem install rubytter
$ sudo gem install oauth
$ sudo gem install oauth
適当なフォルダにRailsプロジェクト作成。
名前は取りあえず『twitter』にしておきましょう。
$ rails twitter
プロジェクトに移動して、コントローラの作成。
index→認証ボタン表示 / ツイートの表示
oauth→認証ボタンを押した時にTwitterに転送する
callback→Twitterから戻ってきた時の後処理
$ cd twitter
$ ruby script/generate controller index index oauth callback
$ ruby script/generate controller index index oauth callback
TwitterへのConsumer登録。
これからアクションとテンプレートをガリガリ書いていきます。
と、その前に、大事な事を忘れていました。
OAuth経由でTwitterにアクセスする場合、コンシューマ登録が必要となります。
http://twitter.com/oauth_clients

こちらから登録して、Consumer KeyとConsumer Secretを取得してください。
途中アプリケーションWebサイトとコールバックのURLを入力する欄がありますが、適当なURLでOKです。僕は『http://example.com』と入れました。
準備は出来ましたか?では次に進みましょう。ლ(╹◡╹ლ)
サンプル作成。
親コントローラにRubytterとOAuthのロードと、クラスメソッドを追加。
Consumer KeyとConsumer Secretは自分で取得した物に置き換えてください。
/app/controllers/application_controller.rb
require 'oauth'
require 'rubytter'
class ApplicationController < ActionController::Base
helper :all
protect_from_forgery
protected
def consumer
OAuth::Consumer.new(
'*** Consumer Key ***',
'*** Consumer Secret ***',
{ :site => "http://twitter.com" }
)
end
end
require 'rubytter'
class ApplicationController < ActionController::Base
helper :all
protect_from_forgery
protected
def consumer
OAuth::Consumer.new(
'*** Consumer Key ***',
'*** Consumer Secret ***',
{ :site => "http://twitter.com" }
)
end
end
まずはTwitterの認証に飛ぶためのボタンを設置。indexコントローラは空のままで良いので、テンプレートを書きましょう。
/app/views/index/index.html.erb
<% form_tag :action => 'oauth' do |f| %>
<%= submit_tag '認証する' %>
<% end %>
<%= submit_tag '認証する' %>
<% end %>
ひとまずここでサーバーを動かしてみましょうか。
プロジェクトのルートで以下のコマンド。
$ ruby script/server
ブラウザで『http://localhost:3000/』にアクセス。あれ?Welcomeページが表示されました。

気を取り直して、Welcomeページ(/public/index.html)を削除。
ルートでindexコントローラーが使えるように、ルーティングも変えましょう。
/config/route.rb
ActionController::Routing::Routes.draw do |map|
map.root :controller => 'index'
map.connect ':action', :controller => 'index'
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
map.root :controller => 'index'
map.connect ':action', :controller => 'index'
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
ブラウザに戻ってページをリロード。

ちょっと寂しいですが、自分の作ったものが表示されました。
次はoauthアクションを書きましょう。『:oauth_callback』はコールバック先のURLを指定してください。今回は『callback』にしておきます。
/app/controllers/index_controller.rb
def oauth
#Twitterから未認可のrequest tokenを発行してもらう
request_token = self.consumer.get_request_token(
#コールバックURLの指定
:oauth_callback => "http://#{request.host_with_port}/callback"
)
session[:request_token] = request_token.token
session[:request_token_secret] = request_token.secret
#未認可のrequest tokenをURLに含め、Twitterの認証画面にリダイレクト
redirect_to request_token.authorize_url
end
#Twitterから未認可のrequest tokenを発行してもらう
request_token = self.consumer.get_request_token(
#コールバックURLの指定
:oauth_callback => "http://#{request.host_with_port}/callback"
)
session[:request_token] = request_token.token
session[:request_token_secret] = request_token.secret
#未認可のrequest tokenをURLに含め、Twitterの認証画面にリダイレクト
redirect_to request_token.authorize_url
end
ここまで書いて再びブラウザに戻ります。
先程のボタンをクリック。Twitterに転送されます。『Allow』ボタンを押してコンシューマからのアクセスを許可してください。

ボタンを押すと、先程指定したコールバックURLに転送されます。
まだ何も書いてないので空ページが表示されます。

では、次に行きましょう。
/app/controllers/index_controller.rb
def callback
consumer = self.consumer
#許可済みのrequest tokenをaccess tokenと交換する
request_token = OAuth::RequestToken.new(
consumer,
session[:request_token],
session[:request_token_secret]
)
access_token = request_token.get_access_token(
{},
:oauth_token => params[:oauth_token],
:oauth_verifier => params[:oauth_verifier]
)
#access tokenが正しいか検証
response = consumer.request(
:get,
'/account/verify_credentials.json',
access_token, { :scheme => :query_string }
)
case response
when Net::HTTPSuccess
@user_info = JSON.parse(response.body)
unless @user_info['screen_name']
flash[:notice] = "Authentication failed"
redirect_to :action => :index
end
else
RAILS_DEFAULT_LOGGER.error "Failed to get user info via OAuth"
flash[:notice] = "Authentication failed"
redirect_to :action => :index
return
end
#正しいaccess tokenと判明したので、セッションに保存しておく
#request tokenはもう要らないので破棄
session[:request_token] = nil
session[:request_token_secret] = nil
session[:oauth] = true
session[:oauth_token] = access_token.token
session[:oauth_verifier] = access_token.secret
redirect_to :action => :index
end
consumer = self.consumer
#許可済みのrequest tokenをaccess tokenと交換する
request_token = OAuth::RequestToken.new(
consumer,
session[:request_token],
session[:request_token_secret]
)
access_token = request_token.get_access_token(
{},
:oauth_token => params[:oauth_token],
:oauth_verifier => params[:oauth_verifier]
)
#access tokenが正しいか検証
response = consumer.request(
:get,
'/account/verify_credentials.json',
access_token, { :scheme => :query_string }
)
case response
when Net::HTTPSuccess
@user_info = JSON.parse(response.body)
unless @user_info['screen_name']
flash[:notice] = "Authentication failed"
redirect_to :action => :index
end
else
RAILS_DEFAULT_LOGGER.error "Failed to get user info via OAuth"
flash[:notice] = "Authentication failed"
redirect_to :action => :index
return
end
#正しいaccess tokenと判明したので、セッションに保存しておく
#request tokenはもう要らないので破棄
session[:request_token] = nil
session[:request_token_secret] = nil
session[:oauth] = true
session[:oauth_token] = access_token.token
session[:oauth_verifier] = access_token.secret
redirect_to :action => :index
end
indexのテンプレートも編集。
/app/views/index/index.html.erb
<% if flash[:notice] %>
<div id="notice"><%= flash[:notice] %></div>
<% end %>
<% unless session[:oauth] %>
<% form_tag :action => 'oauth' do |f| %>
<%= submit_tag '認証する' %>
<% end %>
<% else %>
Twitterに認証されたよ!
<% end %>
<div id="notice"><%= flash[:notice] %></div>
<% end %>
<% unless session[:oauth] %>
<% form_tag :action => 'oauth' do |f| %>
<%= submit_tag '認証する' %>
<% end %>
<% else %>
Twitterに認証されたよ!
<% end %>
再びアクセスしてみましょう。
indexのボタンクリック→Twitterに転送、『Allow』ボタンをクリック→戻ってくる。

おお!認証されました。
でも、これだけじゃ面白くないので、Twitterからつぶやきを持ってきましょう。
つぶやきを表示する。
indexコントローラのindexアクションを編集
/app/controllers/index_controller.rb
def index
#認証されている場合、自分のタイムラインを持ってくる
if session[:oauth]
#一度認証された後はaccess tokenだけでアクセス出来る
token = OAuth::AccessToken.new(
self.consumer,
session[:oauth_token],
session[:oauth_verifier]
)
rubytter = OAuthRubytter.new(token)
@friends_timelines = rubytter.friends_timeline
end
end
#認証されている場合、自分のタイムラインを持ってくる
if session[:oauth]
#一度認証された後はaccess tokenだけでアクセス出来る
token = OAuth::AccessToken.new(
self.consumer,
session[:oauth_token],
session[:oauth_verifier]
)
rubytter = OAuthRubytter.new(token)
@friends_timelines = rubytter.friends_timeline
end
end
indexのテンプレートを再度編集。
/app/views/index/index.html.erb
<% if flash[:notice] %>
<div id="notice"><%= flash[:notice] %></div>
<% end %>
<% unless session[:oauth] %>
<% form_tag :action => 'oauth' do |f| %>
<%= submit_tag '認証する' %>
<% end %>
<% else %>
<div id="friends_timeline">
<dl>
<% for f in @friends_timelines do %>
<dt><%= image_tag f.user.profile_image_url, {:width => 40, :height => 40} %></dt>
<dd><%= f.user.name %></dd>
<dd><%= f.text %></dd>
<% end %>
</dl>
</div>
<% end %>
<div id="notice"><%= flash[:notice] %></div>
<% end %>
<% unless session[:oauth] %>
<% form_tag :action => 'oauth' do |f| %>
<%= submit_tag '認証する' %>
<% end %>
<% else %>
<div id="friends_timeline">
<dl>
<% for f in @friends_timelines do %>
<dt><%= image_tag f.user.profile_image_url, {:width => 40, :height => 40} %></dt>
<dd><%= f.user.name %></dd>
<dd><%= f.text %></dd>
<% end %>
</dl>
</div>
<% end %>
ページをリロード。自分のタイムラインが表示されました。

まとめ。
全部で100行もないコードでこれだけの事が出来ました。
ライブラリ開発者様に感謝です。
というか、そもそも僕がこの記事を書いた目的。
僕は前々からTwitterのクライアントを作ってみたいと思っていました。たまたま目にしたRailsでTwitterのOAuthを試すの記事を見て、Ruby/Railsの勉強を兼ねて実際に作ってみました。作ってみたんですが、うまく動かないというか、期待してた動きと違ってたんです。どうやら僕が理解してた(と思ってた)OAuthの概念と実際のOAuthの動きに差異があったようです。で、半泣きになりながら色々な記事を参照したりサンプルを見たりして試行錯誤してました。その経緯を自分の備考録としてまとめるためと、また、僕と同じようにOAuthの概念がイマイチよく分からなくてハマる人がいるんじゃないか?と思って書きました。え?いないですか?そうですか。しかし、実際に手を動かして試したり、この記事を書くために色々な記事を参照することで、自分の理解を深めることが出来ました。ლ(╹◡╹ლ)
もし『この記事読んで余計分らなくなったぞこの野郎!』って人がいましたらコメントかTwitterにて優しく突っ込みを入れてください。ごめんなさい。
参考リンク。
ゼロから学ぶOAuth:第1回 OAuthとは?―OAuthの概念とOAuthでできること
OAuthの概念について。今読むととても理解出来るんですが、最初はよく分かりませんでした。実際に手を動かして作ってみるのが良いと思います。
Ruby OAuth GEM
RubyライブラリOAuthの公式サイト。
RailsでTwitterのOAuthを試す
RubyのライブラリOAuthの使い方。
今回書いた記事のほとんどはここを参考/引用させて頂いております。
jugyo's rubytter at master - GitHub
RubyライブラリRubytterのGithub。
Rubytter
RubyライブラリRubytterの使い方。ライブラリ作者様のブログ。
rubytter と oauth を使う
OAuthとRubytterの連携方法。
この記事へのコメント
1. Posted by JironBach 2010年09月06日 17:49
何でIDとパスワードだけじゃ認証できないんだろう?
って疑問に思ってたんですが
このページのサンプルをコピペして動かしたら
だんだん意味がわかってきました。
とても参考になりました。
ありがとうございます。