2010-11-23
Ruby on Rails で Facebookアプリを作る (和訳)
-------------------------------------
[2011/04/02追記]
地域コミュニティ系です。よろしければご利用ください。
http://apps.facebook.com/jimocities/
-------------------------------------
※2011/04/04 現在、FacebookはFBMLの廃止を宣言しています。
Graph API を用いた開発が今後のメインストリームになっていきそうです。
-------------------------------------
facebookアプリをrailsで作ろうと思って色々検索してみたのだが
あまり日本語の情報がなかったので著者(Jonathon Horsman さん)
の許可をもらって
http://www.arctickiwi.com/blog/developing-facebook-applications-for-ruby-on-rails
の記事を和訳してみました。
英語勉強中の身で拙いと思いますので、変なところあったらご指摘いただけると幸いです。
以下和訳
--------------------------------
このエントリは ruby on rails で facebookアプリを開発するときのために
書かれたものですが、内容の多くの部分は特定の言語に縛られず、他の言語で開発する
場合においても有用なものとなっていると思います。
雑感
おそらくそれが苦痛に満ちた行程をたどることになるとすぐに気づくでしょう。
APIは頻繁に更新されますが、ドキュメントは大抵古いもので、
今読んでいるものが現在も正しいものであるか確証は持てません。
Facebook developers wiki http://wiki.developers.facebook.com/
には、メインページに古い情報であることの注意が書かれていますが、
内容の殆どはまだ信頼性に足り、有用であることが多いです。
official developers site http://developers.facebook.com/
の情報は紛らわしい用語が使われていて、初めに観るものとしては少し難しいものです。
もしあなたがfacebookアプリの開発をすぐにでも始めるとしたら、
行程の始まりから終わりまでとてつもなくストレスフルなものとなるでしょう。
また、問題を解決することは難しく(しかもそれは頻繁に発生します)、面倒なトライアンドエラーの繰り返しを行うことになります。
Facebook Connectと ソーシャルプラグイン
Facebookと用意したサイトの統合は、ソーシャルプラグインと呼ばれる
コンポーネントやウィジェットを設置することによって行います。
また、facebook上にアプリケーションを設置する場合は、開発者のサーバが
Faebook Connectをコールすることで実現します。
後者の場合は、まず初めにユーザにアプリをインストールさせるために、開発者のサイトにアクセスさせます。アプリがインストールされると、プロフィールページのアプリリストにインストールされたアプリが表示されるようになるはずです。
FBMLとiframes
facebook関連サービスを作ろうとするとき、まず二つの選択肢があります。
一つは FBML (HTML with a few Facebook extentions の略)を用いた方法、
もう一つは、facebookを経由せず、自分で用意したサーバからiframeのhtmlを直接レスポンスし、
facebookのページにエンベデッドする方法です。
FBMLを用いた開発では、facebookサイトが特定のページへのリクエストとして開発者が用意したサーバに
アクセスし、FBML tag等を解析し、適切なhtmlやJavaScriptにそれらを変換し、クライアントに返します。
iframeを用いた開発では、開発者がfacebookを経由せずに、ダイレクトにコンテンツをクライアントに返します。
ここで、注意しなければいけないのはXFBMLを使用することです。
XFBMLはFBMLのような一連のタグですが、facebookサーバがそうする代わりに、
クライアント側のJavaScriptによってhtmlを含んだタグを解析し変換します。
XFBMLは以下のように動作します。
1 クライアントのブラウザが ttp://app.facebook.com/your-app のようなURLを通して
開発者の用意したアプリケーションにアクセスします。このURLのページの中央には
iframeが置かれています。
2 ブラウザがiframeを通して開発者の用意したサーバのURLにアクセスします。
3 開発者の用意したサーバがHTMLとXFBMLによるデータをクライアントにダイレクトに返します。
それらはfacebookが用意したjavascriptの読み込み宣言が含まれているものになります。
4 ページのロードが終わってから、facebookの用意したjavascriptが実行され、全てのタグを解析し
HTMLに変換します。このHTMLにはfacebookからコンテンツを引っ張ってくるためのもの(URL?)が含まれています。
上記の仕組みの利点は
http://developers.facebook.com/search?q=Choosing_between_an_FBML_or_IFrame_Application
で議論されています。開発者たちにとって一番重要な要素は、スピードです。
facebookの全てのページの右下に置かれている小さなチャットボックスは、
素直にレンダリングしようとすると、大きく、動作が遅くなりがちなものです、
開発者はiframe中のコンテンツのクリックで様々な機能を提供することにより、
不要なローディングのオーバーヘッドを回避できる、
つまり、アクセス時毎回発生するiframeの外のコンテンツのリロードを回避することができます。
マイナスの面としては、ページをリロードした際の遅延が挙げられます。
もし開発者が Facebook XFBML tagsをページで使っていたら、それらのコンテンツは
javascriptが実行され、facebokサーバにリクエストを飛ばし、結果が返り、それらのページ上での
レンダリングが終わってから表示されることになります。
ですので、ユーザーにはfacebookのコメントボックスやlikeボタンが表示される前に、ローディングアイコン
が表示され待たされているように見えるはずです。
iframeの代わりにFBMLを用いる方法を選び Ruby on Railsでアプリを開発する場合の困りごととしては、
facebookが全てのリクエストをpostで行うことが挙げられます。
この点は明らかにRuby on Railsの restfulなルーティングを無視しており、
開発者はおそらくroutes.rbに書かれている全てのアクションのルーティング設定を
手作業で書かなければいけないであろうことを示しています。
開発者がFBMLを選ぶかiframeを選ぶかに関わらず、facebook API はクライアント側でもサーバ側でも
使うことができます。
サーバ側では、「ensure_authenticated_to_facebook」のような、それらAPIの便利なラッパーである
favebooker gem を使いました。
facebooker gemを使うと、レスポンスタイムが400ミリ秒ほど余計に掛かるようになってしまい、
facebookサーバへのヒット数を最少に抑える必要がありましたが、クライアントサイドで
facebook apiを叩くようにすることでなんとかすることが出来ます。
開発者のオフィスからファイヤーウォールを通して
facebookアプリケーションをデプロイする時に伴う不都合な点は、
デプロイしないとテストができないことです。
たくさんの偶然によって、開発環境の予期できなかった不都合や方法論の選択ミスが浮き彫りになります。
ちゃんと動くか試してみて、だめだったら動くまで繰り返す..。
30秒ごとに強制的にデプロイするようにすることはこの問題をさらにうんざりさせるものにさせ、
サーバ上で直接開発する方がまだマシでした。(うわぁ)
それでは始めましょう
facebookアプリの開発を始めるにはいくつかしなければいけないことがあります。
この時、facebook developer application を登録必要があります。
あなたのアプリケーションの設定を変更する必要があることにも注意してください。
develop appllication にアクセスし、My Application を探してください。
・アプリケーションを作ったら、apiキーとsecretキーを取得してください。
これらはfacebook API を叩く時に必要となります。
configディレクトリの中に facebooker.ymlファイルを作ってください。
以下のような感じになります。
development: api_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx secret_key: yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy canvas_page_name: yoursite callback_url: http://yourapp.yoursite.com pretty_errors: true set_asset_host_to_callback_url: true test: api_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx secret_key: yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy canvas_page_name: yoursite callback_url: http://yourapp.yoursite.com pretty_errors: true set_asset_host_to_callback_url: true
・Railsのviewのコードをいじるとき、layoutの中にhamlによるhtmlタグで
%html{html_attrs('en'), "xmlns:fb" => "http://www.facebook.com/2008/fbml"}
<html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml' xmlns:fb='http://www.facebook.com/2008/fbml'>
・同様にlayoutの中でIE6対策として以下のような空divを足してください。
・そしてその直下に以下のようにXFBMLの処理を全て司るjavascriptを追加してください。
<%= javascript_include_tag "http://static.ak.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php" %>
詳細なURLを記述すべきことに注意してください。
いくつかのドキュメントに省略されたURLを使う方法が記述する方法を見たことがありますが、
おかしな挙動の原因となるのでおすすめしません。
このように書いた方が堅実に動くようと思います。
・xd_receiver.htm というファイルをpublicディレクトリに置いてください
中身はこういう感じです。
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Cross-Domain Receiver Page</title></head><body><script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.js?2" type="text/javascript"></script></body></html>
これによってiframe内のアプリケーションと外側のfacebook間でクロスドメインの通信が
可能になります。
開発開始
以上の準備が完了すれば、もう開発が始められます。
開発は、railsの機能 modelやcontorller、viewを使って行われます。
まずはaplication_controller.rbの中で全体的な認証処理をするのと、
facebookウィジェットをあなたのページに置くことから始めましょう
ユーザにコメントを残してもらいたいページがあるとします。
これを実現するには、該当のページでfb_commentsを使うだけです。
(詳細についてはfacebookerのドキュメントを参照してください。)
fb_comments "arbitrary-unique-id-123", true, false, 20, :callbackurl => "http://app.facebook.com/your-app/your-url", :width => 613
メインページのURLは常に
http://app.facebook.com/your-app
で始まり、その後に続くものはiframeのURLとして置かれます
つまり、http://app.facebook.com/your-app/photo/1
のパスへのアクセスとなります。
カレントユーザのチェック
カレントユーザの確認を含む私たちのアプリケーションの一部は
特定のページのファンページです(?)
facebookはそれらの用語を「being a fan」から「liking」に変えました。
昔のいくつかのドキュメントたapiコールでは「fan」という古い
用語を使っていましたが、ほとんど同じ意味です。
私たちのアプリケーションコントローラではユーザーがfacebookにログイン
しているかどうかをまずチェックします。そして次にアプリケーションを
インストールさせます。
def likes_group?
return true if RAILS_ENV == "development"
return current_session.is_fan(1234567890, current_session.user.uid)
end
def current_session
if @facebook_session && !@facebook_session.expired?
return @facebook_session
end
ensure_authenticated_to_facebook # redirects to the facebook login URL
end
開発環境であったらfacebook api を叩かないという小細工をしています。
internet explorer 6 & 7 に関するバグ
IE6, 7 のcookieでクッキーをうまく扱うには以下のコードを
aplication_controller.rbに加えてください。
class ApplicationController < ActionController::Base ... before_filter :set_p3p def set_p3p response.headers["P3P"]='CP="CAO PSA OUR"' end end
railsを使っていない人は、単純に
"P3P"ヘッダを全てのレスポンスに含めるようにしてください。
絶対ホストパスを設定する
FBMLを使い、画像等やその他のページ内でリンクを貼りたいリソースを使用する場合、
ダイレクトに開発者サーバにリクエストするリンクを生成するときに(http://〜を含む)絶対パスのホストで指定する必要があるでしょう。
もし相対パスであったら、facebookのホストにリクエストを送ってしまうからです。
ApplicationControllerで以下のようにdefault_url_optionsメソッドをオーバーライド
してください。
def default_url_options(options)
{:host => "myapp.mysite.com"}
end
Facebookから来たユーザーを認証する
他のウェブページにエンベデッドされるiframeとしてウェブページを表示するため、
他のサイトを経由せずにユーザー認証をしたい、また、開発したサイトに直接
アクセスしたい時があります。
他のサイトを経由したり、直接開発者のページに直接アクセスするようなことを、ユーザがしてないか確か目たい時があります。
(直接アクセスするには、Firefoxであれば 該当のiframe上で右クリックし、
このフレーム→このフレームだけを表示 で表示できます)
残念なことに上記を行う簡単でイケてる方法はありません。一番いい方法は
FacebookがiframeのURLに付けるパラメータを確認する方法です。
Facebookは fb_sig_in_iframe=1 のようないくつかのパラメータをURLに付与します。
もしあなたが望むのであれば
http://wiki.developers.facebook.com/index.php/Verifying_The_Signature
に書いてあるとおり、hashを使った方法もありますが、これは複雑です。
終わりに
これで大体、私たちがfacebookアプリケーションを開発する際につまずいた部分はカバーしました。
このエントリが、あなたの開発を効率よく進ませる手助けになれば幸いです。
---------------------------------
>他のサイトを経由せずにユーザー認証をしたい、また、開発したサイトに直接
>アクセスしたい時があります
は原文の
>you may want to ensure people don’t bypass the outer page and go directly to your site
に相当すると思うのですが、これは
・ユーザ認証を他のサイトを経由せずに行ったり、開発サイトに直接アクセスしたい
ではなく、
・他のサイト(具体的にはiframeが埋め込まれているfacebookのページ)を迂回したり、直接開発者のページに直接アクセスするようなことを、ユーザ「が」してないか確かめる
ではないでしょうか。
ご返信遅れましてすみません。
ご指摘ありがとうございます。お恥ずかしいです。。
修正させていただきました。ありがとうございました。
かなり拙い訳だったのですが少しでもお役に立てたのなら幸いです。