2012年1月14日土曜日

rubyのoauth2を使ってfacebook連携

rubyのoauth2を使ってfacebookとのOAuth連携を試みてみた。環境は以下の通り。
  • ruby: 1.9.2p180
  • oauth2: 0.5.2
まずは、facebook認証のURLを生成するコードを書いてみる。
require 'oauth2'

site = "https://graph.facebook.com"
token_url= "/oauth/access_token"
key="xxxx"                          # facebookのAPP ID
secret="xxx"                        # facebookのAPP SECRET
callback_url="http://xxx.com/"      # callbackしてほしいURL

#インスタンス作成
client = OAuth2::Client.new(key,secret,:site => site,:token_url => token_url)

#URL作成
url = client.auth_code.authorize_url( :redirect_uri => callback_url)

#URL表示
puts url
これで出来たURLでアクセスすると、facebookのログイン画面が出るので、そこでログインすると次のようなLocationを指定したリダイレクト要求のレスポンスが返ってくる。

Location: (callbackしほしいURL)/?code="(認証コード)"

次に認証コードを使って、tokenを取得するスクリプトを書いてみる。
require 'oauth2'

site = "https://graph.facebook.com"
token_url= "/oauth/access_token"
key="xxxx"                          # facebookのAPP ID
secret="xxx"                        # facebookのAPP SECRET
callback_url="http://xxx.com/"      # callbackしてほしいURL
code ="xxxx"                        # 前のスクリプトで取得したcode

#インスタンス作成
client = OAuth2::Client.new(key, secret, :site => site, :token_url => token_url)

#tokenの取得
access_token = client.auth_code.get_token( code, { :redirect_uri => callback_url })

#token表示
puts access_token.token
これを実行すると、以下のようなエラーがでた。
/usr/local/lib/ruby/gems/1.9.1/gems/oauth2-0.5.2/lib/oauth2/client.rb:129:in `get_token': OAuth2::Error (OAuth2::Error)
まったくわからなかったので、ソースを見ると、問題の個所はこのようになっており、
      response = request(options[:token_method], token_url, opts)
      raise Error.new(response) if options[:raise_errors] && !(response.parsed.is_a?(Hash) && response.parsed['access_token'])
ここのoptions[:raise_errors]というのがtrueのため例外を飛ばしていることが分かった。
原因を調査していると、githubの掲示板にこのことが書いてあり、acvwilsonさんが解決策を書いてくれている。
まとめると「facebookからのレスポンスの形式(=が入っているやつ)に対応できていないので、以下のコードを追加してパーサを対応させてくれ。」とのこと
OAuth2::Response.register_parser(:text, 'text/plain') do |body|
  key, value = body.split('=')
  {key => value}
end
これを追加するとうまく動いた!

2012年1月9日月曜日

herokuをつかってみる(デプロイ編)

前回、アカウント登録〜SSH鍵登録まで行った。 今回は、HelloWorldアプリのデプロイまでやってみる。 環境は以下の通り
  • OS: Linux (CentOS 5.5)
  • Ruby: 1.9.2
  • git: 1.7.4
公式HPのGetting Started with Rails 3.0 on Heroku/Cedarにしたがって実施。 まず、herokuのgemをインストール
# gem install heroku
続いて、railsのアプリ作成
# rails new myapp # cd myapp
作ったアプリをpostgresql用に変更。Gemfileの「gem 'sqlite3'」を「gem 'pg'」に変更して、「bundle install」を実行することによりGemfile.lockを更新する。
# bundle install
次にgitに登録。
# git init
# git add .
# git commit -m "init"
次に、herokuにstackを作る。
# heroku create --stack cedar
Invalid gemspec in [/usr/local/lib/ruby/gems/1.9.1/specifications/heroku-2.18.0.gemspec]: invalid date format in specification: "2012-01-09 00:00:00.000000000Z"
Invalid gemspec in [/usr/local/lib/ruby/gems/1.9.1/specifications/term-ansicolor-1.0.7.gemspec]: invalid date format in specification: "2011-10-13 00:00:00.000000000Z"
/usr/local/lib/ruby/site_ruby/1.9.1/rubygems.rb:925:in `report_activate_error': Could not find RubyGem heroku (>= 0) (Gem::LoadError)
エラー発生。Gemのロードエラーとのこと。 とりあえず、gemspecのフォーマットエラーが出てるので、エラーを解消してみる。 解消の仕方は、多少強引だが、エラーになっている.gemspacファイルの"2011-10-13 00:00:00.000000000Z"の部分を、読めるフォーマットの"2011-10-13"に書き直す。 再度実行。
# heroku create --stack cedar
Creating warm-sunrise-9514... done, stack is cedar
http://warm-sunrise-9514.herokuapp.com/ | git@heroku.com:warm-sunrise-9514.git
Git remote heroku added
今度はうまくいった。 これで、herokuに 「warm-sunrise-9514」という名前のアプリができる。 「heroku list」コマンドで確認できる。
# heroku list growing-snow-4642
また、herokuのWebサイトにログインしても確認できる。 ちなみに「--stack cedar」というののが意味不明だが、「cedar」は、rails3用のアプリのコンテナ(?)的なものらしく、rails3を使う場合は、これを指定しないといけないらしい。miagoさんのブログに解説されています。 また、作られたアプリ名が「warm-sunrise-9514」とこれまた意味不明だが、 これはherokuが勝手にランダムに二つの単語をつなげてアプリ名にするようです。 後でWebサイトかえられます。 いよいよデプロイ。 ローカルのgitのレポジトリを、herokuにpushすることによりデプロイができる。
# git push heroku master
これも問題なく完了。 その後は、railsでdbを初期化するために以下を実行
# heroku run rake db:migrate
seedもいれてみる。
heroku run rake db:seed

herokuをつかってみる(アカウント登録〜SSH鍵登録)

rails3をherokuで使ってみようと思い、試みる。環境は以下の通り。
  • OS: Linux (CentOS 5.5)
  • Ruby: 1.9.2
公式HPに従ってユーザアカウントの作成。
そして、heroku-clientのダウンロード。
# wget http://assets.heroku.com/heroku-client/heroku-client.tgz
# tar zxvf heroku-client.tgz
さっそくherokuへログインを試みる。
# cd heroku-client
# ./heroku
すると以下のようなエラーが発生。
/usr/local/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require': no such file to load -- readline (LoadError)
どうやら、readlineのrequireに失敗している模様。
tetu1984の日記を参考にさせてもらい、readlineをインストール。
まず、OSにインストール。
# yum install readline-devel
次に、rubyのextentionをインストール。
# cd ruby-1.9.2-p180/ext/readline
# ruby extconf.rb
# make
# make install
再度herokuへのログインを試みる。
# ./heroku login
Enter your Heroku credentials.
Email: xxxx@xxxx.xxxx
Password:
Could not find an existing public key.
Would you like to generate one? [Yn] Y
Generating new SSH public key.

Uploading ssh public key /root/.ssh/id_rsa.pub
/root/heroku-client/lib/heroku/auth.rb:195:in `read': No such file or directory - /root/.ssh/id_rsa.pub (Errno::ENOENT)
エラー発生!
どうやら、初回ログイン時にSSHの鍵ペアを作成して、herokuに登録する動きのようだ。
デフォルトでは、秘密鍵「~/.ssh/id_rsa」と公開鍵「~/.ssh/id_rsa.pub」を作ろうとする。

しかし、私の環境では、前者の秘密鍵がすでに別の用途で存在していて、かつ公開鍵が存在していないために、エラーが起きたっぽい。
解決策は、デフォルトとは違う名前で鍵を作る。
本家のホームページにデフォルトから変える場合の手順が書いてあった。
どうやら、SSHの鍵ペアを作り、「heroku key」の引数を渡せば渡せばよいっぽい。
まずSSHの鍵ペアを作る。
# ssh-keygen -t rsa -f heroku.key
そして、herokuに公開鍵登録。
# ./heroku keys:add ~/.ssh/heroku.key.pub
Uploading ssh public key /root/.ssh/heroku.key.pub
確認。
# ./heroku keys
=== 1 key for xxxx@xxx.xxx
ssh-rsa AAxxxxxx...6gx7ek4w== xxx@xxx.xxx
できた。

heroku-clientがsshする時に使う秘密鍵ファイルがわからないはずなので、sshのconfigを書いておく。
# vi ~/.ssh/config
Host heroku.com
User git
Port 22
Hostname heroku.com
IdentityFile ~/.ssh/heroku.key ←作った秘密鍵

ちなみに、herokuに登録したSSHの公開鍵を消すには、以下のようにすればよい。

まず、以下のコマンドでSSHの公開鍵の名前を調べる。
$ heroku keys
=== 1 key for joe@example.com
ssh-dss AAAAB8NzaC...DVj3R4Ww== joe@workstation.local←これが鍵の名前

そして、「heroku key:remove」。
$ heroku keys:remove joe@workstation.local
Key joe@workstation.local removed.

詳しくは、公式ドキュメント参照