Hatena::ブログ(Diary)

某社文系エンジニアの日記

2010-11-23

Ruby on Rails で Facebookアプリを作る (和訳)

16:29 |

-------------------------------------

[2011/04/02追記]

facebookアプリを作ってみました。

地域コミュニティ系です。よろしければご利用ください。

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 railsfacebookアプリを開発するときのために

書かれたものですが、内容の多くの部分は特定の言語に縛られず、他の言語で開発する

場合においても有用なものとなっていると思います。

雑感

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等を解析し、適切なhtmlJavaScriptにそれらを変換し、クライアントに返します。

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 Railsrestfulなルーティングを無視しており、

開発者はおそらくroutes.rbに書かれている全てのアクションのルーティング設定を

手作業で書かなければいけないであろうことを示しています。

開発者がFBMLを選ぶかiframeを選ぶかに関わらず、facebook APIクライアント側でもサーバ側でも

使うことができます。

サーバ側では、「ensure_authenticated_to_facebook」のような、それらAPIの便利なラッパーである

favebooker gem を使いました。

facebooker gemを使うと、レスポンスタイムが400ミリ秒ほど余計に掛かるようになってしまい、

facebookサーバへのヒット数を最少に抑える必要がありましたが、クライアントサイドで

facebook apiを叩くようにすることでなんとかすることが出来ます。

開発者のオフィスからファイヤーウォールを通して

facebookアプリケーションデプロイする時に伴う不都合な点は、

デプロイしないとテストができないことです。

たくさんの偶然によって、開発環境の予期できなかった不都合や方法論の選択ミスが浮き彫りになります。

ちゃんと動くか試してみて、だめだったら動くまで繰り返す..。

30秒ごとに強制的にデプロイするようにすることはこの問題をさらにうんざりさせるものにさせ、

サーバ上で直接開発する方がまだマシでした。(うわぁ)


それでは始めましょう

facebookアプリの開発を始めるにはいくつかしなければいけないことがあります。

・あなたのアプリケーション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タグで

xml名前空間を宣言するようにしてください。

%html{html_attrs('en'), "xmlns:fb" => "http://www.facebook.com/2008/fbml"}

hamlがいやだったら、普通の生htmlでも大丈夫です。

<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

は、開発者のサーバの /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アプリケーションを開発する際につまずいた部分はカバーしました。

このエントリが、あなたの開発を効率よく進ませる手助けになれば幸いです。

---------------------------------

七誌七誌 2011/02/07 14:07 素晴らしく有益な情報ありがとうございます

七誌七誌 2011/02/07 14:26 自分の英語力も拙いものなのであまり自信が無いのですが、ひとつ違うんじゃないかと思った箇所があります

>他のサイトを経由せずにユーザー認証をしたい、また、開発したサイトに直接
>アクセスしたい時があります
は原文の
>you may want to ensure people don’t bypass the outer page and go directly to your site

に相当すると思うのですが、これは
・ユーザ認証を他のサイトを経由せずに行ったり、開発サイトに直接アクセスしたい
ではなく、
・他のサイト(具体的にはiframeが埋め込まれているfacebookのページ)を迂回したり、直接開発者のページに直接アクセスするようなことを、ユーザ「が」してないか確かめる

ではないでしょうか。

hkwebhkweb 2011/02/13 02:58 >七誌さん
ご返信遅れましてすみません。
ご指摘ありがとうございます。お恥ずかしいです。。
修正させていただきました。ありがとうございました。
かなり拙い訳だったのですが少しでもお役に立てたのなら幸いです。