Twitter投稿をデータベースアプリケーションで自動化する
合唱音源の新着情報を運営してきて 真面目に分析 するにあたり、 1600件程度の自由形式なテキストデータを都度grepして分類・集計するのは限界だと思いました。
Twitter上のテキストデータをマスタとするのではなく構造化されたデータベースをマスタとして扱い、そこから集計をかけたりtwitterに投稿したくなりました。
要するに、合唱音源の新着情報専用のtwitterクライアントを作る事にしました。
要件
- 投稿内容を「作曲者」「曲名」といった音源の属性にひも付けて集計できる
- 予約投稿ができる
設計
分類や複雑な条件の検索に強いRDBMSを使い、どこからでも投稿できるようWebアプリケーションとします。
使用技術
Microsoft Azure 仮想マシン
サーバにはMicrosoftが提供するIaaSである Azure 仮想マシン を使います。
この程度の用途ならVPSで十分?MicrosoftのVPSがありますか?ありませんよね。
Ruby on Rails 4 (on Apache Passenger)
という理由でRailsを採択しました。
なのでCSSはプリプロセッサ(Sass)を使います。SassとSaaSって紛らわしい。
CentOS 6.5
さすがにIISでRailsは修羅の道と判断しUNIXを選択。なおDockerみたいなオシャレな方法は使いません。OneNoteにサーバ構築の秘伝のタレが溜まっていきます。
ちなみに、AzureのPaaSを使ってRailsを動かす方法もあるようですが...
TypeScript
CoffeeScriptで十分?それはMicrosoftが作っていますか?作っていませんよね。
SQLite3
SQL Server?あーあー聞こえない
インフラの構築
まずAzureで最小構成のA0インスタンスを立ち上げ、 過去に書いた記事 と同様の方法でRailsのProduction環境を立ち上げます。
以下を見ながらWebサーバをWebrick→Apacheに変更。 (今回の用途ならばWebrickでも十分ですが…)
- Apache上でRuby on Railsアプリケーションを動かす/Passenger(mod_rails for Apache)の利用 — Redmine.JP
- gem - Getting remove_entry_secure error while using ruby application - Stack Overflow
また、メモリが足りなくて後述のAssetCompileが落ちてしまったので、下記方法でSwap領域を作っておきます。 (AWS EC2もAzure VMも同じくSwap領域がありません)
アプリケーションの開発
DB設計は下記の通り、シンプルなm対n構造を用います。
下記のように、モデルクラスに has_many
や belongs_to
を記述するだけのシンプルな記法でこういったリレーションが利用できます。こういうのがActiveRecordを使いたかった理由です。
class Tweet < ActiveRecord::Base has_many :tweet_maps has_many :tweet_details, through: :tweet_maps end
class TweetDetail < ActiveRecord::Base has_many :tweet_maps has_many :tweets, through: :tweet_maps end
class TweetMap < ActiveRecord::Base belongs_to :tweet belongs_to :tweet_detail end
↑こうするだけで、↓こういう事ができます。
<% tweet.tweet_details.each do |detail| %> <li><%= detail.value %></li> <% end %>
RailsAdmin
バックエンド画面は少々作りこむ必要があるのですが、とりあえず最低限のものを自動で作ってくれるRailsAdminを導入。
- RailsAdmin | Railsで管理画面を自動生成 - Qiita
- Ruby - RailsAdminセットアップ on Rails4 and Heroku - Qiita
- RailsAdminでRails管理画面を作成 | EasyRamble
- Rails4 にて Devise でユーザー登録・ログイン認証・認可の機能を追加 | EasyRamble
rails_admin自体をカスタマイズしていく方法もあるようですが、下記のようにあまり使いやすいとは言えません。 また、hamlという謎の記法を覚えなければ容易に手を付けられないようです。
- rails_adminをカスタマイズする方法まとめ - Qiita
- rails_admin/dashboard.html.haml at master · sferik/rails_admin · GitHub
とりあえず、そのままにして使います。
twitter
という名前そのまんまのgemがあり、こちらを用いると簡単にtwitter投稿機能を実装することができます。
RailsでTwitter botを作成 | EasyRamble
whenever
データベースに登録した内容を常に確認し、指定した時間に投稿するタスクスケジューラが必要です。
LinuxのcrontabをRailsで適当に取り扱うgemが whenever
です。
これらを使い、
whenever
で投稿すべきデータが無いか毎分チェックするtwitter
で投稿する
# schedule.rb set :environment, @environment every '* * * * *' do rake "twitter:tweet" end
# taskの中 tweet_data = Tweet.where("tweet_status = ? AND reserve_at < ?", 0, Time.now).order("created_at ASC").limit(1).first next unless tweet_data tweet = client.update(tweet_data.tweet_text.chomp) tweet_data.update(:tweet_status => 10, :tweet_uri => tweet.uri.to_s)
当然のようにソースコード中にアクセストークン等すべてベタ書きなため一部抜粋です。よい子は真似しないこと。 先に挙げさせていただいたブログにもある通り、Rails4.1から実装されたsecret.ymlにでも書いてgitignoreするべきでしょう。
twitter文字数判定
twitterには文字数制限があり、プログラムでバリデーションをかけたいと思います。
twitterの文字数制限は140文字ですが、URLは短縮されたり何だかんだ色々なルールがあり、厳密にカウントするのは難しいです。
特に合唱音源の新着情報はURLを多く含むため、単純に length <= 140
等でバリデートしてしまうと片っ端から弾かれてしまい使い物になりません。
しかしそこはtwitter社、文字数判定などに使うプログラムを自らgithubに上げています。
これらを用いれば、正確な文字列判定などを実装できるそうです。まだ使っていませんが。
Railsバージョンアップ
開発途中でRailsのバージョンが上がっていったため、それに追従させました。
Ruby on Rails の大掃除! 3.2 → 4.1 にバージョンアップするの巻 - komiyakの通り道
上記を参考に、4.0.3から4.1.9にバージョンアップしました。 (4.2はrails_adminが上手く動かなさそうだったのでやめました)
手順自体は簡単で、Gemfileのバージョン番号を変えて bundle update
と rake rails:update
を打つだけです。
リリース前ならばやりたい放題です。
デプロイ
本プロジェクトはコスト削減のために本番サーバをリモートリポジトリにしております。すなわちrsyncやcapistranoのようなオシャレ技術は使うまでもなく、本番サーバに入り下記コマンドを黙々と実行すればデプロイ完了です。 シェルスクリプトにすらなっていない秘伝のタレです。
git rebase origin/master master bundle install rake db:migrate RAILS_ENV=production rake assets:clobber rake assets:precompile RAILS_ENV=production service httpd graceful; service httpd status
先述のSwap領域を作っていないとprecompileで落ちる事があります。
リリース
wheneverでcronを仕込み、バックエンド画面から予約投稿を登録してしばし待ちます。 感動の瞬間です。
合唱団イクトゥス
周藤諭 編曲
『Happy Birthday to You』
http://t.co/IPNZGfSsq4
— 合唱音源の新着情報 (@s2terminal) 2015, 2月 14
いつもと同じ投稿なのですが、こうして普通に表示され、普通にリツイートが来ているのを見ると幸せな気分になります。
なおこの方法で投稿した発言の特徴として、twiccaやTweetDeckなど一部のTwitterクライアントで見える使用クライアント名がAPI申請時に登録したアプリケーション名 「合唱音源の新着情報」 となります。
「TweetDeck」「TwitterWebClient」から「合唱音源の新着情報」に切り替わっています。
結論
たったこれだけの事に丸1年かかりました。
その間ずっとAzureのサーバ代も払っています。すしを2回たべられる程度のお金をMicrosoftに寄付しました。
感想としてはクリエイティブな箇所に時間を割くために、構築やデプロイに工数をかけたくありません。つまりAzureのPaaSでRailsが使いたいと思いました。それherokuで良いじゃん