Ruby on Rails + devise + omniauth + whenever で Twitter bot を作る

シェアする

なんとなく Twitter の bot を作りたくなったので Rails を使ってやってみた。twitter の bot 動かすだけなら Rails 使う必要もないんだけど、devise とか omniauth とか使ってみたかったのでお試しということで。

多分、以下のような感じに作れるが作業ログに見落としがあるかもしれない。

github にもあげた。

Sponsored Links

Twitter アプリの登録

Twitter Application Management からアプリを以下のような感じに作成する。

twitter-app-settings-for-bot

URL は各自の環境に合わせて設定しよう。

Rails アプリの作成

$ rails new twitter-bot
$ cd twitter-bot

Twitter アプリ作成時に取得した Consumer Key と Consumer Secret を config/secrets.yml に記述する。

development:
    secret_key_base: c889ef...
    twitter_api_key: CONSUMER_KEY
    twitter_api_secret: CONSUMER_SECRET

必要な Gem の追加

Gemfile に以下を追加する。

gem 'devise'
gem 'omniauth-twitter'
gem 'twitter'
gem 'whenever'

記述したら bundle install する。

devise の設定

認証を行う為の gem である devise を設定する。

$ rails g devise:intall

config/initializers/devise.rb に以下を記述する。

config.omniauth :twitter, Rails.application.secrets.twitter_api_key, Rails.application.secrets.twitter_api_secret

ユーザの作成

user モデルを作成する。

$ rails g model user provider uid access_token access_token_secret

rails g devise user 使ってもいいけど、どうせ大したことしないので普通にモデル作ってる。

このへんは以下のページを参考にした。

コマンドを実行したら db/migrate/ 以下にある create_users.rb を編集する

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :provider
      t.string :uid
      t.string :access_token
      t.string :access_token_secret

      t.timestamps
    end
    add_index :users, [:provider, :uid], unique: true
  end
end

編集したらデータベースに反映させる。

$ rake db:migrate

app/models/user.rb を編集し、devise で omniauth を利用する際の処理及び Twitter で認証した際に習得できるデータを DB に保存できるようにする。

ついでに Twitter API を扱うための処理も入れておく。

class User < ActiveRecord::Base
    devise :omniauthable

    def self.from_omniauth(auth)
        where(provider: auth["provider"], uid: auth["uid"]).first_or_create do |user|
            user.provider = auth["provider"]
            user.uid = auth["uid"]
            user.access_token = auth["credentials"]["token"]
            user.access_token_secret = auth["credentials"]["secret"]
        end
    end

    def twitter
        @client ||= Twitter::REST::Client.new do |config|
            config.consumer_key        = Rails.application.secrets.twitter_api_key
            config.consumer_secret     = Rails.application.secrets.twitter_api_secret
            config.access_token        = access_token
            config.access_token_secret = access_token_secret
        end
    end
end

こうしておけば user.twitter.update('hogehoge') みたいな感じに Twitter を扱えるようになる。

omniauth での認証

Twitter で認証する際に呼ばれるコールバック関数を作成する。

$ mkdir app/controllers/users/
$ vi app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
    def twitter
        @user = User.from_omniauth(request.env["omniauth.auth"])

        if @user.persisted?
            sign_in_and_redirect @user, :event => :authentication
            set_flash_message(:notice, :success, :kind => "Twitter") if is_navigational_format?
        else
            session["devise.twitter_data"] = request.env["omniauth.auth"]
            redirect_to new_user_registration_url
        end
    end
end

ログイン画面の作成

app/views/layouts/application.html.erb の <body>直下に以下を記述する。

<% if user_signed_in? %>
    <%= link_to "Sign out", destroy_user_session_path %>
<% else %>
    <%= link_to "Sign in with Twitter", user_omniauth_authorize_path(:twitter) %>
<% end %>
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>

ルーティングの設定

config/routes.rb を以下のように設定する。

Rails.Application.routes.draw do
  root "home#index"
  get "home/index"
  devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
  devise_scope :user do
    get 'sign_out', :to => 'devise/sessions#destroy', :as => :destroy_user_session
  end

ここまでやれば rails s でサーバ起動して Sign in with Twitter でログインし、アクセストークンをデータベースに保存できると思う。

tweet task の作成

自動で呟く際に実行するタスクを作成する。

$ rails g task tweet
$ vim lib/tasks/tweet.rake

ユーザ認証しているアカウント全部で呟く処理を書く。

namespace :tweet do
    task :autotweet => :environment do|t, args|
        User.all.each do |user|
            user.twitter.update('ひるほー')
        end
    end
end
$ rake tweet:autotweet

これでツイートできたらOK

whenever の設定

bot なので自動で呟くための仕組みを導入する。rails であれば whenever を使うのが良いらしい。gem 自体は rails new した直後に設定して入れてあるのでそれを利用する。

詳しくは以下の記事を参照してほしい。

whenever を使って rails で crontab を扱う
Rails で作成した Web アプリで一部の処理を cron で動かしたいと思ったので調べたら whenever を使うのが良さそうだったのでやってみた...
$ bundle exec wheneverize .
[add] writing `./config/schedule.rb'
[done] wheneverized!
$ vim config/schedule.rb
every 1.day, :at => '12:00 pm' do
  rake "tweet:autotweet"
end
$ bundle exec whenever --update-cron --set environment=development

crontab -l でちゃんと反映されているのかを確認できる。これで自動で呟かれていたら OK だ。

Sponsored Link

シェアする

フォローする