2009年12月19日

最近モーニングツイートいうTwitter連携サービスを作ってます。
その備考録も兼ねて。

49)

一応動作環境も。
OS:Mac OS X 10.6.2
Ruby:1.8.7
Rails:2.3.5

RubyとRailsがインストールされてる前提で話を進めます。

最後にライブラリの説明や僕が参考にさせて頂いた記事へのリンクをまとめておきますのでそれをご参照ください。


ライブラリのインストールとプロジェクトの作成。

まずはRubytterとOAuthをインストール。
$ sudo gem install rubytter
$ sudo gem install oauth

適当なフォルダにRailsプロジェクト作成。
名前は取りあえず『twitter』にしておきましょう。
$ rails twitter

プロジェクトに移動して、コントローラの作成。
index→認証ボタン表示 / ツイートの表示
oauth→認証ボタンを押した時にTwitterに転送する
callback→Twitterから戻ってきた時の後処理
$ cd twitter
$ ruby script/generate controller index index oauth callback


TwitterへのConsumer登録。

これからアクションとテンプレートをガリガリ書いていきます。
と、その前に、大事な事を忘れていました。
OAuth経由でTwitterにアクセスする場合、コンシューマ登録が必要となります。

http://twitter.com/oauth_clients
49)

こちらから登録して、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


まずはTwitterの認証に飛ぶためのボタンを設置。indexコントローラは空のままで良いので、テンプレートを書きましょう。
/app/views/index/index.html.erb
<% form_tag :action => 'oauth' do |f| %>
  <%= submit_tag '認証する' %>
<% end %>

ひとまずここでサーバーを動かしてみましょうか。
プロジェクトのルートで以下のコマンド。
$ ruby script/server

ブラウザで『http://localhost:3000/』にアクセス。あれ?Welcomeページが表示されました。
55)


気を取り直して、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

ブラウザに戻ってページをリロード。
01)

ちょっと寂しいですが、自分の作ったものが表示されました。

次は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に転送されます。『Allow』ボタンを押してコンシューマからのアクセスを許可してください。
49)

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


では、次に行きましょう。
/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

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 %>



再びアクセスしてみましょう。
indexのボタンクリック→Twitterに転送、『Allow』ボタンをクリック→戻ってくる。
20)
おお!認証されました。
でも、これだけじゃ面白くないので、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

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 %>


ページをリロード。自分のタイムラインが表示されました。
48)


まとめ。

全部で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の連携方法。

mitukiii at 14:46│この記事をクリップ!プログラム | Web

この記事へのコメント

1. Posted by JironBach   2010年09月06日 17:49
5 最初はoauthの意味が全然分からなくて
何でIDとパスワードだけじゃ認証できないんだろう?
って疑問に思ってたんですが
このページのサンプルをコピペして動かしたら
だんだん意味がわかってきました。
とても参考になりました。
ありがとうございます。