Skip to content

Rails3でRubytterを使ってTwitterマッシュアップアプリを作る

|

RailsでOAuthとRubytterを使ってTwitterクライアントを作る
一年ほど前にこんな記事を書きました。情報が古くなってしまったのと、僕が新規にTwitterマッシュアップアプリを今作ってるということで、書き直すことにしました。

動作確認環境

Mac OS X 10.6.6
ruby 1.9.2p136
Rails 3.0.3

完成イメージ図


TwitterをOAuth経由で認証し、タイムラインを表示する簡単なものです。

想定読者

Rubyはある程度書ける。
Rails3については分からない。(Rails2、または他のMVCフレームワークを使用したことがある。)
OAuthの仕組みもよく分からない。

RubyとRailsはインストールされてる前提で話を進めます。インストールについては他の記事をご参照ください。また、Rubyについての解説もしません。Rails3については適当に説明を入れてあります。テストは書いてありますが、Twitterマッシュアップアプリを作るということに焦点を当てるため、省きます。また、コードはDiff風に書いてあります。

プロジェクトの作成

まずはrails newコマンドでプロジェクトの作成。

$ rails new rails3-twitter --skip-active-record --skip-test-unit
      create
      create  README
      create  Rakefile
      create  config.ru
      create  .gitignore
      create  Gemfile
      create  app
      create  app/controllers/application_controller.rb
      create  app/helpers/application_helper.rb
      create  app/mailers
      create  app/models
      create  app/views/layouts/application.html.erb
      create  config
      create  config/routes.rb
      create  config/application.rb
      create  config/environment.rb
      create  config/environments
      create  config/environments/development.rb
      create  config/environments/production.rb
      create  config/environments/test.rb
      create  config/initializers
      create  config/initializers/backtrace_silencers.rb
      create  config/initializers/inflections.rb
      create  config/initializers/mime_types.rb
      create  config/initializers/secret_token.rb
      create  config/initializers/session_store.rb
      create  config/locales
      create  config/locales/en.yml
      create  config/boot.rb
      create  db
      create  db/seeds.rb
      create  doc
      create  doc/README_FOR_APP
      create  lib
      create  lib/tasks
      create  lib/tasks/.gitkeep
      create  log
      create  log/server.log
      create  log/production.log
      create  log/development.log
      create  log/test.log
      create  public
      create  public/404.html
      create  public/422.html
      create  public/500.html
      create  public/favicon.ico
      create  public/index.html
      create  public/robots.txt
      create  public/images
      create  public/images/rails.png
      create  public/stylesheets
      create  public/stylesheets/.gitkeep
      create  public/javascripts
      create  public/javascripts/application.js
      create  public/javascripts/controls.js
      create  public/javascripts/dragdrop.js
      create  public/javascripts/effects.js
      create  public/javascripts/prototype.js
      create  public/javascripts/rails.js
      create  script
      create  script/rails
      create  tmp
      create  tmp/sessions
      create  tmp/sockets
      create  tmp/cache
      create  tmp/pids
      create  vendor/plugins
      create  vendor/plugins/.gitkeep

DBを使わないのでActiveRecord(という名前のORM)をスキップします。また、僕はテストフレームワークにTest::UnitではなくRSpecを使用しているためTest::Unitのスキップします。ここは適当に読み替えてください。その他のオプションは「$ rails new –help」で見ることが出来ます。

RubytterをGemfileに記述しインストール

Rails3ではBundleという仕組みで使用するGemを管理します。使用するGemはGemfileに書く必要があります。今回はRubytterというTwitterライブラリを使用するので、その指定をGemfileに記述します。また、上記した通り僕はRSpecを使用しているので、開発時とテスト時にRSpecを使用するという記述もしています。

Gemfile

 source 'http://rubygems.org'

 gem 'rails', '3.0.3'
+gem 'rubytter'
+group :development, :test do
+  gem 'rspec-rails', '>= 2.3.0'
+end

Gemfileに記述したGemはプロジェクトルートで「$ bundle install」というコマンドを実行することでインストールします。アプリケーションを動かすのに足りないものがあれば、全てまとめてインストールされます。

$ bundle install
Fetching source index for http://rubygems.org/
Using rake (0.8.7)
Using abstract (1.0.0)
Using activesupport (3.0.3)
Using builder (2.1.2)
Using i18n (0.5.0)
Using activemodel (3.0.3)
Using erubis (2.6.6)
Using rack (1.2.1)
Using rack-mount (0.6.13)
Using rack-test (0.5.7)
Using tzinfo (0.3.24)
Using actionpack (3.0.3)
Using mime-types (1.16)
Using polyglot (0.3.1)
Using treetop (1.4.9)
Using mail (2.2.14)
Using actionmailer (3.0.3)
Using arel (2.0.7)
Using activerecord (3.0.3)
Using activeresource (3.0.3)
Using bundler (1.0.7)
Using diff-lcs (1.1.2)
Using json (1.4.6)
Using oauth (0.4.4)
Using thor (0.14.6)
Using railties (3.0.3)
Using rails (3.0.3)
Using rspec-core (2.4.0)
Using rspec-expectations (2.4.0)
Using rspec-mocks (2.4.0)
Using rspec (2.4.0)
Using rspec-rails (2.4.1)
Using rubytter (1.4.1)
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.

コントローラとルーティングを作成する

コントローラは「$ rails generate controller」で作成出来ます。indexコントローラと、その下にindex, oauth, callbackのアクションを作成します。アクションはそれぞれ、認証ボタンの表示/ツイートの表示、認証ボタンを押した時にTwitterに転送する、Twitterから認証された時の後処理、に使用します。

$ rails generate controller index index oauth callback
      create  app/controllers/index_controller.rb
       route  get "index/callback"
       route  get "index/oauth"
       route  get "index/index"
      invoke  erb
      create    app/views/index
      create    app/views/index/index.html.erb
      create    app/views/index/oauth.html.erb
      create    app/views/index/callback.html.erb
      invoke  rspec
      create    spec/controllers/index_controller_spec.rb
      create    spec/views/index
      create    spec/views/index/index.html.erb_spec.rb
      create    spec/views/index/oauth.html.erb_spec.rb
      create    spec/views/index/callback.html.erb_spec.rb
      invoke  helper
      create    app/helpers/index_helper.rb
      invoke    rspec
      create      spec/helpers/index_helper_spec.rb

ルーティングを書き換えて、”/”, “/oauth”, “/callback”というURLでアクションにアクセス出来るようにします。

config/routes.rb

 Rails3Twitter::Application.routes.draw do
-  get "index/index"
+  root to: "index#index", as: :index
-  get "index/oauth"
+  get "/oauth" => "index#oauth", as: :oauth
-  get "index/callback"
+  get "/callback" => "index#callback", as: :callback

Twitterへのアプリケーション登録

大事なことを忘れていました。OAuth経由でTwitterにアクセスするためには、アプリケーション登録をしConsumer KeyとConsumer Secretを取得する必要があります。

http://twitter.com/oauth_clients

今回作成するのはブラウザアプリケーションのため、”アプリケーションの種類”はブラウザアプリケーションをチェックします。Webサイトは公開予定のURLか、またはhttp://example.com/と入れておきましょう。コールバックURLの指定もありますが、これは認証時に上書きすることが出来るので、適当なものでも大丈夫です。

Consumerを取得するラッパーメソッドを作成

ApplicationControllerにConsumerのインスタンスを取得するラッパーメソッドを作成します。’consumer key’, ‘consumer secret’と書かれた部分は自分で取得したものに置き換えてください。

app/controllers/application_controller.rb

 class ApplicationController < ActionController::Base
   protect_from_forgery
+
+  protected
+  def self.consumer
+    OAuth::Consumer.new(
+      'consumer key',
+      'consumer secret',
+      {site: "http://twitter.com"}
+    )
+  end
+
 end

認証ボタンを作成

Twitterの認証に飛ぶためのボタンを作成します。

app/views/index/index.html.erb

-<h1>Index#index</h1>
-<p>Find me in app/views/index/index.html.erb</p>
+<% form_tag :oauth, method: :get do |f| %>
+  <%= submit_tag '認証する' %>
+<% end %>

また、プロジェクト作成時に作成されたWelcomeページは要らないので削除します。

$ rm public/index.html

ひとまずここでサーバを動かしてみましょう。「$ rails server」コマンドで起動出来ます。

$ rails server

http://0.0.0.0:3000/にアクセスして確認してみます。

そっけないながらもボタンが表示されました。

OAuthアクションを作成

認証ボタンを押した時にTwitterに転送するためのoauthアクションを作成します。

app/controllers/index_controller.rb

   def oauth
+    callback_url = "http://#{request.host_with_port}/callback"
+    request_token = self.class.consumer.get_request_token(oauth_callback: callback_url)
+
+    session[:request_token] = {
+      token: request_token.token,
+      secret: request_token.secret
+    }
+
+    redirect_to request_token.authorize_url
   end

Twitterから未認可のrequest tokenを発行して貰うためにOAuth::Consumerのインスタンスからget_request_tokenメソッドを呼びます。これでOAuth::RequestTokenのインスタンスを取得出来ます。また、この時にcallback先としてcallbackアクションのURLを指定します。発行して貰ったrequest tokenは後からまた使うのでtokenとsecretをセッションに保存しておきます。認証するためのURLはOAuth::RequestTokenのauthorize_urlメソッドで取得することが出来るので、そのURLにリダイレクトさせます。

Callbackアクションを作成

Twitterから認証された時の後処理するためのcallbackアクションを作成します。

   def callback
+    if params[:denied]
+      session.delete :oauth
+    else
+      request_token = OAuth::RequestToken.new(
+        self.class.consumer,
+        session[:request_token][:token],
+        session[:request_token][:secret]
+      )
+
+      access_token = request_token.get_access_token(
+        {},
+        oauth_token: params[:oauth_token],
+        oauth_verifier: params[:oauth_verifier]
+      )
+
+      session[:oauth] = {
+        token: access_token.token,
+        secret: access_token.secret
+      }
+    end
+
+    session.delete :request_token
+
+    redirect_to :index
   end

まず、認証拒否された時です。認証拒否された時はdeniedパラメータが送られてきます。セッションに前回以前に保存されたoauth tokenがあった場合削除します。indexにリダイレクトをかけます。

次に、認証された時です。セッションに保存しておいたrequest tokenとrequest secretを復元してOAuth::RequestTokenのインスタンスを作成します。oauth_tokenとoauth_verifierパラメータが送られてくるので、OAuth::RequestTokenのget_access_tokenメソッドに渡し、access token(oauth token)と交換します。これでOAuth::AccessTokenのインスタンスが取得出来ます。request tokenは用済みなので、セッションから削除し、代わりにaccess tokenとaccess secretをセッションに保存します。これ以降はaccess tokenを使ってTwitterにアクセスすることが出来ます。

OAuthで認証する

この時点で、OAuth経由でTwitterに認証してもらうことが出来るようになりました。試してみましょう。

indexページ表示。"認証する"ボタンをクリック。

認証画面へリダイレクト。"許可する"ボタンをクリック。

転送中...。

callbackアクションを経由して再びindexページへ。

タイムラインを表示する

認証まで出来ました。次は、indexページで認証されてる場合にフレンドタイムラインを表示するようにしましょう。

app/controllers/index_controller.rb

   def index
+    return unless session[:oauth]
+
+    access_token = OAuth::AccessToken.new(
+      self.class.consumer,
+      session[:oauth][:token],
+      session[:oauth][:secret]
+    )
+
+    rubytter = OAuthRubytter.new(access_token)
+
+    begin
+      @tweets = rubytter.friends_timeline
+    rescue Rubytter::APIError
+      session.delete :oauth
+    end
   end

認証されいない場合は、何もせずテンプレートを表示します。

認証されていた場合は、セッションに保存していたaccess tokenを取り出してOAuth::AccessTokenのインスタンスを作成します。それを引数にOAuthRubytterのインスタンスを作成します。このインスタンスからツイートしたりタイムラインを取得したり出来ます。フレンドタイムラインの取得はfriends_timelineメソッドです。

ユーザーがaccess tokenを無効化したりアクセスを拒否をした場合はRubytter::APIError例外が投げられます。その場合はセッションのaccess tokenを削除しています。

app/views/index/index.html.erb
(インデントが変わりdiffが見にくいので全体のコードを記します。)

<% unless session[:oauth] %>
  <% form_tag :oauth, method: :get do |f| %>
    <%= submit_tag '認証する' %>
  <% end %>
<% else %>
  <div id="friends_timeline">
    <dl>
      <% @tweets.each do |t| %>
      <dt><%= image_tag t.user.profile_image_url, size: '40x40' %></dt>
      <dd><%= t.user.name %></dd>
      <dd><%= t.text %></dd>
      <% end %>
    </dl>
  </div>
<% end %>

認証されてない場合は認証ボタンを表示、認証済みの場合はタイムラインを表示します。

さて、ブラウザに戻りリロードしてみましょう。タイムラインが表示されました。

まとめ

ほら、簡単でしょ?RailsフレームワークとRubytterライブラリのおかげで少ないコードで認証してタイムラインの表示まですることが出来ます。後は、各々思い描いているTwitterマッシュアップアプリケーショを作成するだけです!

ソースコード

上記ソースコードは、テストコード含め全てGithubに上げてあります。
ライセンスはWTFPLです。
ご自由にお使いください。

mitukiii/rails3-twitter - GitHub

参考リンク

RailsでTwitterのOAuthを試す | おいぬま日報
RailsでのTwitterマッシュアップアプリを書くにあたって、こちらの記事を参考にさせて頂きました。

System.Exit – Rubytter
TwitterのRubyライブラリRubytterの公式ページ/作者様ブログ。

Ruby OAuth GEM
OAuthのRubyライブラリOAuthの公式ページ。

合わせて読みたい

ゼロから学ぶOAuth:第1回 OAuthとは?―OAuthの概念とOAuthでできること
OAuthの概念について。読んでも最初はよく分からないと思うので手を動かして作ってみるのが良いと思います。

Ruby on Rails3を使ってアプリ作ってみたメモ
僕がRails3を初めて使った時につまづいたところ/分からなかった事のメモと、Rails3についての情報源。

関連記事

2 Comments

  1. 参考にして作ってみました!
    認証ボタンを作成するところで、
    app/views/index/index.html.erb

    -Index#index
    -Find me in app/views/index/index.html.erb
    +
    +
    +
    のところ、

    +
    となっていたのでボタンが出ず、ハマってしまいました。
    +
    と=を入れるとちゃんと動き、ボタンが表示されました。

    良い記事をありがとうございました!!

    2012年04月23日 23時10分 | Permalink
  2. あっ、タグになってコードが表示されていない……。
    % form_tag :oauth, method: :get do |f| %
    の、%のあとの=が抜けていた ということです。
    それと、
    application_controller.rbなのですが、
    {site:”http://twitter.com”}だとJSONのパーサーエラーになってしまったのですが、
    {site:”http://api.twitter.com”}にするとうまくいきました。
    とにかく、良い記事をありがとうございました。

    2012年04月23日 23時55分 | Permalink

One Trackback/Pingback

  1. [...] てはこの記事が参考になると思います。 Rails3でRubytterを使ってTwitterマッシュアップアプリを作る [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*