なんとなく Twitter の bot を作りたくなったので Rails を使ってやってみた。twitter の bot 動かすだけなら Rails 使う必要もないんだけど、devise とか omniauth とか使ってみたかったのでお試しということで。
多分、以下のような感じに作れるが作業ログに見落としがあるかもしれない。
github にもあげた。
https://github.com/ryomatsu/twitter-botTwitter アプリの登録
Twitter Application Management からアプリを以下のような感じに作成する。
https://apps.twitter.comURL は各自の環境に合わせて設定しよう。
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 使ってもいいけど、どうせ大したことしないので普通にモデル作ってる。
このへんは以下のページを参考にした。
http://qiita.com/soramugi/items/5b2ed46e8c8b6157e7ccコマンドを実行したら 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 を扱う | Lonely Mobiler$ 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 だ。