先日公開した「つぶやかレシピ」の技術的な内容について書きます。 使っている技術はざっくり言うと以下のような内容なので興味のある部分があれば参考にしてください。
- Ruby1.9.3+Rails3.2.3
- Ruby Gem Twitterを用いてTwitterAPIを利用
- Nokogiriを用いでCookpadのサイトから情報の一部を引っ張ってきている
- 公開はHeroku
■Herokuへのアップロードについて
- Herokuのアカウントを取る
- ローカルPCでHerokuにログインする(Terminalで)
- Railsのアプリ作る
- gitでpushする
$ gem install heroku
$ heroku login (emailとパスワード入れる)
$ rails new [application name]
$ cd [application name]
$ git init
$ git add .
$ git commit -m “first commit”
--- アプリ作成 とgit add & commitを繰り返す
完成したら
$ heroku create --stack cedar
$ git push heroku master
でデプロイできます。 なお、Rails3.1からProductionモードで動かした時にassetsファイルの読み込み先がdevelopmentモードと違ってて動かなかったりCSS反映してくれなかったりするので、ローカルでもproductionモードで動かしておくのが吉です。
■つぶやかレシピの話
■やってること
■短縮URLへの対応
Twitter検索は、つぶやきが短縮URLになっていても検索時はフルのURLとして検索対象にしてくれる。 しかし、取得してきた文字は短縮URLなので、短縮を展開する必要がある。 短縮URLは Net::HTTPRedirection が返るので以下の様な感じで展開処理を書いています。
def self.getExpandUri(uri)
expandUri = nil
errCd = nil
begin
response = Net::HTTP::get_response(URI.parse(uri))
case response
when Net::HTTPSuccess then
#通常URIの場合
expandUri = uri
when Net::HTTPRedirection then
#短縮URIの場合
expandUri = getExpandUri(response['location'])
else #その他
response.error!
end
rescue => errCd
#ログに書く
logger.error "ERR_CD:#{errCd},uri:#{uri}"
end
return expandUri
end
あと、URLの展開は以下のようにやっているのですが、URL直後に半角英数がくっつていると一緒に持ってきちゃって意図しないURLになります。 (r.textがURLを含んだツイート内容です)
uri = URI.extract(r.text, %w[http]).first
これを外す処理がこれ。
def self.format_uri(uri)
return if uri == nil
case uri.last
when ':', '.', '(', ')', '@'
uri[-1] = ''
self.format_uri(uri)
end
uri.gsub!(/[?].*/, '')
return uri
end
展開後にも、?… というアクセス解析のためのクエリストリングが付いていることがあるので展開後にももう一度やる必要があります。
■定期的なつぶやきの取得 Herokuは無料だとCronが1日1回しか使えません。 cookpadのURLつぶやきは多そうなので1日1回だと不足だと思いました。 やったこと。
- Delayed_jobをつかう→H有料プランじゃないと使えない機能でした。
- 更新用のURLを作って踏む→Herokuは15秒ぐらい以上掛かる処理はアプリケーションエラーになる
- 更新用のURLを作ってすこしずつ取得→うまく行った
少しずつ、というのは6分に1回、10件ずつ処理しています。 具体的には update?token={秘密の文字列} みたいなURLを作って、秘密の文字列が一致していた時のみ更新処理を行うようにしています。 そして、そのURLに対して自分のLinuxマシンから6分毎にcurlしています。
def update_task
@result = false
if params[:token] != ENV['token']
logger.error "authenticate error:#{params[:token]}:#{ENV['token']} does not much"
return
end
#更新処理
Recipe.collect(10, 100, 10)
@result = true
end
※ENVの説明は後でします。 GoogleAppEngineはCronを任意のタイミングで実行できるようなので、そちらも使ってみるとWebサービスだけでうまく処理が完結してくれるのかな、と思います。 ただ、あくまで処理時間を10秒ぐらいで抑えているのでこの対応でうまくいくだけなので、1日に1回とか1時間に1回、数秒とかでは終わらず数分とかかかるような処理をさせるのであればやはりHerokuのCronを使う必要があるのだと思います。
■環境変数ENV
パスワードとかAPIキーとか、ソースはgithubに公開したいけど公開されると困る情報というのがあると思います。 そういうのをソースコード内で ENV['hoge'] としておいて読めるようにする機能。 たとえば上の ENV['token']ですが、こんな感じでHerokuに設定しています。
$ heroku config:add token="homuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomu"
こうしておくと、Rubyのコードでは ENV['token'] で"homuhomu(略)"が返るわけです。 ただし、このENVというのはあくまでHerokuの機能なので単純にやるとローカル環境でのテストや実行が通らなくと思います。 その対応として、秘密の文字列を追加したファイルを作る。(.envなど)そしてそのファイルを.gitignoreなどで構成管理に入らないようにする。 中身はこんな感じで token=homuhomuhomuhomu・・・
RAILS_ROOT/config/initializes/ 以下にこれを読み出してグローバル変数ENVに格納する処理を書けば、ローカルでもENVの部分を解釈してくれるようになります。 例
envfile = Rails.root.join(".env")
if envfile.exist?
envfile.open("r").each do |line|
key, val = line.split("=", 2)
ENV[key] = val.gsub("\n", "") if val != nil
end
end
■参考リンク
- ソースコード ryonext/BestPad
- 前回の記事 月曜日までに考えておきます Twitterで話題のクックパッドレシピを表示するWebアプリをリリースしました
- つぶやかレシピ つぶやかレシピ ~Twitterで話題のレシピ~
お世話になったサイト