【Ruby on Rails】twitter apiを利用してoauth認証・タイムラインを表示する

2018年9月21日Rubyapi, oauth, Rails, REST API, Ruby, Twitter, タイムライン

週末プログラミング、皆さんやっていますか?

こんにちは。現在、管理人はRuby on RailsでTwitterやFacebook、Instagramといった各種SNSのapiを叩き、oauth認証機能を利用したりタイムラインを引っ張ってきたりするプログラムを書いています。

後々は同じインターフェース内で全てのSNSのタイムラインを表示させるサービスを完成させる予定ですが、それまでの機能的な部分を切り取ってご紹介しています。

twitter apiは構造自体は簡単!でもapi利用制限が多く、方法もたくさんあるために意外と難しかった

twitter apiは非常に利用制限が厳しく、15分間に15回までしか叩けない場合もあります。

また、Railsの場合gemを導入して簡単に実装するのが良いのですが、いかんせん多すぎてどれが良いのかよく分かりません。

僕の環境で動いた一例として、以下をお読みください。

Twitter apiを叩くための便利なgemを入れておこう

## twitter api 関連 ##
gem 'twitter'
gem 'oauth'
gem 'omniauth-twitter'

これらは問答無用で入れておきましょう。(環境:Rails 4.2.4, ruby 2.0.0p645 (2015-04-13 revision 50299) [universal.x86_64-darwin15])

Railsの良いところであり悪いところでもあるのですが、これらのgemを導入すると、簡単なコードを書くだけでtwitter apiを叩けます。

しかし、それぞれのメソッドが何をしているのか理解するために導入したgemのソースコードの中身を確認しておくことは必要です。

omniauth.rbを設定しよう(/config/initializers/omniauth.rb)(ファイル名も一致させないと動きません)

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :twitter, Rails.application.secrets.twitter_consumer_key, Rails.application.secrets.twitter_consumer_secret
end

omniauth.rbにtwitterのconsumer_keyやconsumer_secretを設定してもいいのですが、それらはsecrets.ymlに格納しておくのがイケてる(らしい)です。

secrets.ymlに自身のconsumer_keyとconsumer_secretを書いておこう(/config/secrets.yml)

default: &default
  twitter_consumer_key: 'あなたのconsumer_key'
  twitter_consumer_secret: 'あなたのconsumer_secret'

development:
  <<: *default
  secret_key_base: **

test:
  <<: *default
  secret_key_base: **

# Do not keep production secrets in the repository,
# instead read values from the environment.

## 本番環境では下記のように読み込むことで、あなたのconsumer_keyとかを悪用されませんよ、という書き方(らしい) ##
production:
  twitter_consumer_key: <%= ENV["TWITTER_CONSUMER_KEY"] %>
  twitter_consumer_secret: <%= ENV["TWITTER_CONSUMER_SECRET"] %>
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

instagram apiをRuby on Railsで叩くでも紹介しましたが、twitter apiを叩く時に必要なconsumer_keyとconsumer_secretの取得方法を以下に紹介します。

Twitter開発者用ページ(https://dev.twitter.com/)にアクセス!

以下の白枠内をクリックすると、自分のappsページに飛べます。(これマジで分かりにくくて毎度探すのに時間かかるんだけど、Twitterさん何とかして)

次に、自分専用のアプリを登録します。

次はアプリの名前や説明、リダイレクト先等を入力しましょう。(Callback URLを適切に書かないと動作しません。)

最後にconsumer_keyとconsumer_secretを確認しましょう。

上記2項目をsecrets.ymlに書き込みましょう。

ちなみにpermissionは今は気にしなくてOKです。(ユーザーがoauth認証する際に聞かれるもので、基本Read and Writeに設定しておけば良いでしょう。ただし、不要なpermissionは要求しないようにするのがマナーです。)

routes.rbはこんな感じ(/config/routes.rb)(RailsのREST fulなルーティングが分かっていません。参考程度にしてください。)

Rails.application.routes.draw do
  root 'home#index'
  get "home/index"
  
  # twitter routes
  get "/tweet" => "tweet#timeline"
  get "/signout_twitter" => "sessions#destroy"
  
  # Oauth routes ←api叩くと/auth/twitter/callbackにリダイレクトされます。session生成しています。
  get "/auth/:provider/callback" => "sessions#create" 
end

一応簡易的なサインインとサインアウト機能作っておきました。

sessions_controller.rbでログインもどきの動き入れました。(/app/controllers/sessions_controller.rb)

class SessionsController < ApplicationController
  ## session生成 ##
  def create
    ## URLがtwitterからのリダイレクトURLの場合、sessionにアクセストークンを格納する。 ##
    ## ↑これセキュリティー上ダメかな。笑 ##
    if (request.path_info == "/auth/twitter/callback")
      auth = request.env["omniauth.auth"]
      session[:oauth_token] = auth.credentials.token
      session[:oauth_token_secret] = auth.credentials.secret
      session[:username] = auth.extra.access_token.params[:screen_name]
      redirect_to "/tweet", :notice => "サインイン!"
    else
      redirect_to root_url
    end
  end

  ## sesion破棄 ##
  def destroy
    session[:oauth_token] = nil
    session[:oauth_token_secret] = nil
    redirect_to root_url, :notice => "サインアウト!"
    if (request.path_info == "/signout_twitter")
      session[:username] = nil
    end
  end
end

内容としてはシンプルで、上記のコードで簡単にoauth認証を実装できています。gem最高。Rails最高。

これ、ちなみにPHPで書くとアホみたいにコード量増えます。びっくり。(参考:https://syncer.jp/twitter-api-matome)

tweet_controller.rbで実際にタイムラインを表示してみます。(/app/controllers/tweet_controller.rb)

class TweetController < ApplicationController
  ## viewで使うメソッドはヘルパーメソッドに ##
  helper_method :timeline

  ## これ書かないとgemが動きません ##
  require 'twitter'

  ## twitter apiを叩いてタイムラインを表示する ##
  def timeline
    ## 何でこれ書いてるんだろう...多分無くても動く気はします ##
    client = Twitter::REST::Client.new do |config|
      config.consumer_key = Rails.application.secrets.twitter_consumer_key
      config.consumer_secret = Rails.application.secrets.twitter_consumer_secret
      config.access_token = session[:oauth_token]
      config.access_token_secret = session[:oauth_token_secret]
    end

    client.home_timeline(:count => 200).each do |tweet|
      ## 作りかけで恐縮ですが...二重配列にRT数などの要素を格納する予定です ##
      @array = Array.new
      @total_array = Array.new
      text = tweet.full_text
      fav = tweet.favorite_count
      rt = tweet.retweet_count
      @weight = fav + rt * 1.5
      @array = [text, fav, rt, @weight]
      p @array
    end
  end
end

後はviewを作っておけば、タイムラインを表示できます。

application.html.erbのリンク先だけ気をつけて!(/app/views/layouts/application.html.erb)

<!DOCTYPE html>
<html>
  <head>
  <title>SocialLog</title>
  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
  <%= csrf_meta_tags %>
  </head>
  <body>
    <div id="container">
      <div id="user_nav">
        <% if signed_in? %>
          ようこそ! <%= session[:username] %>
        <% end %>
        <%= link_to "twitterにサインイン", "/auth/twitter" %>
      </div>
    <%= yield %>
    </div>
  </body>
</html>

リンク先のpathを/auth/twitterに設定しておけば問題ありません。(必ず登録したURLに一致させましょう。)

いかがですか?

これで自分のタイムラインを表示することができたと思います。

Railsの場合、gemが優秀すぎてtwitter apiを扱うのは本当に手軽です。ぜひやってみてくださいね!

2018年9月21日Rubyapi, oauth, Rails, REST API, Ruby, Twitter, タイムライン