Herokuで作るFacebookアプリ

第6回Facebookに投稿してみよう

はじめに

前回は、Facebook APIについて学びました。Facebook APIの使い方のイメージができたかと思います。今回は、実際にFacebook APIを呼び出して情報を取得したり投稿したりする部分の実装を見ながら、APIの使い方を学んでいきましょう。

第4回で作成したアプリのソースを元に、rest-graph gemで認証部分の再実装を行い、マンガを登録できるようにします。そして、登録したことを自分自身のWallに投稿するという機能を実装します。

今回のアプリのサンプルは、こちらになります。少し動作させてみて、動きを確認していただけると良いかと思います。また、アプリケーションのソースコードはこちらになります。必要に応じてご覧いただければと思います。

rest-graphを用いた認証

第4回で、Herokuでサンプルとして紹介されているOmniAuthを用いたOAuthでの認証連携のコードを解説しました。しかし、今回作るアプリはFacebook専用であるためOmniAuthでなくもっとFacebookに特化したgemを利用して認証を行うことのほうが簡単に連携できます。前回の記事でこのあたりの方式の違いについては解説しています。

今回は、rest-graphというgemを用いてFacebookとの連携を行います。このgemはHerokuのFacebookアプリの事例として紹介されているCardinal Blue社が公開しているものなので信頼性も高いのではないかと考えています。

該当のコミットは、こちらになります。重要な変更点は、app/controllers/application_controller.rb になります。

include RestGraph::RailsUtil

before_filter :filter_setup_rest_graph, :set_current_user

helper_method :current_user

private
def filter_setup_rest_graph
  rest_graph_setup(:auto_authorize => true, :write_cookies => true)
end

def set_current_user
  @current_user = User.find_or_create_by_rest_graph!(rest_graph)
end

def current_user
  @current_user
end

include RestGraph::RailsUtil を実行することによりincludeしたコントローラでRestGraphの提供するRailsのコントローラ向けのユーティリティーメソッドが利用できるようになります。

rest_graph_setupメソッドを呼ぶことで、Canvasの認証やOAuthの認証などFacebookの対応するほぼ全ての認証方式を自動的にカバーして認証を行います。JavaScript SDKを利用する場合は、 :write_cookies => true のオプションを指定しておくと認証がサーバ側とJavaScript側でCookieを通してやり取りすることで共用することができます。

その後、rest_graphというオブジェクトに認証情報が格納されているので、set_current_userメソッドの中でそれを利用して現在のログインユーザの情報を取得しcurrent_userメソッドで取り出せるように設定しています。このように実装することで、Railsでよく見る認証方式と同じように扱えるようになりました。

もう1つのポイントとして、config/initializers/rest_graph_config.rbを見てください。

module EnvDefaults
  def default_app_id
    ENV["FACEBOOK_APP_ID"]
  end

  def default_secret
    ENV["FACEBOOK_APP_SECRET"]
  end
end

RestGraph.send(:extend, EnvDefaults)

このように実装することで、Herokuらしくアプリの鍵情報などを環境変数から設定できるようになります。直接ファイルに書きこむことも可能ですが、今回ソースが公開されることもあり環境変数で指定する形を取りました。

パーミッション(権限)の追加

今回実装したいのは、マンガを登録した際に自動的に本人のWallに登録したというFeedを流すことです。一般的にソーシャルの関係を利用して、利用者数を拡大するためによく使われる方法です。これを実現するには、JavaScript SDKから投稿するか、Graph APIをサーバから呼び出して投稿するのか2パターンが考えられます。JavaScriptの場合は、ユーザがキャンセルする操作などが存在し、必ず投稿することを強制したいのでGraph APIを呼び出す方式を実装したいと思います。

Facebookでは、APIを呼び出す際にパーミッションの考えがでてきます。通常、rest-graphを利用してCanvasでアプリを動かすと与えられるパーミッションは標準のパーミッション(読み込み)のみが設定されている状態になります。今回追加のパーミッション(書き込み)を取得する必要があります。これを実現するには、JavaScript SDKを利用するのがユーザにとってシームレスになります。

では、JavaScript SDKを用いてパーミッションを追加する方法を見ていきましょう。こちらのコミットが該当する差分になります。まずは、JavaScript SDKを利用出来るようにjavascriptの呼び出しなどを行います。app/views/layouts/application.html.haml のファイルになります。

#fb-root
:javascript
  window.fbAsyncInit = function() {
    FB.init({appId: '#{RestGraph.default_app_id}', status: true, cookie: true, xfbml: true});
  };
  (function() {
    var e = document.createElement('script'); e.async = true;
    e.src = document.location.protocol +
      '//connect.facebook.net/en_US/all.js';
    document.getElementById('fb-root').appendChild(e);
  }());

このようにFacebookが提供しているjavascriptファイルを読み込んで、FB.initメソッドなどを呼び出し初期化を行います。

次に、実際にパーミッションを必要とするのはマンガを登録しようとする時でその際にパーミッションがなければ要求のダイアログが表示されるようにしようと思います。public/javascripts/application.jsに主な処理は記載されています。

$(document).ready(
  function(){
    $("#amazon-items").find('.post input').click(
      function(){
        var $this = $(this);
        FB.login(function(response){
                   if (response.perms) {
                     $this.parents("form").submit();
                   } else {
                     alert('You must allow to access Facebook data from manga-dojo.');
                   }
                 },
                 { perms: 'publish_stream, offline_access' }
                );
        return false;
      }
    );
  }
);

登録ボタンが押された際に、jQueryでフックしてFB.loginメソッドを呼び出して必要なパーミッション(⁠⁠publish_stream, offline_access⁠⁠)を指定しています。パーミッションの要求ダイアログは以下のように表示されます。

パーミッションの要求ダイアログ
パーミッションの要求ダイアログ

このようにして、投稿などが必要なアプリの場合は、パーミッションを要求すると良いと思います。

投稿処理

最後に、目的の処理である投稿部分を見ていきましょう。この部分の差分はこちらです。app/models/user.rb を見ていきましょう。

def post_feed(options = {})
  logger.debug "[POST/feed] #{options.inspect}"
  self.client.post("me/feed", options) unless mock?
end

def client
  @client ||= RestGraph.new(:access_token => self.oauth_token)
end

このように、clientメソッドでデータベースのトークンの情報からRestGraphのインスタンスを取得して、post_feedメソッドで実際にFacebook側に投稿します。この部分は非常にシンプルですね。rest-graphが上手くラッピングしてくれているおかげです。

まとめ

今回は、FacebookのGraph APIとJavaScript SDKを上手く利用して、強制的にWallにFeedを追加するということができました。これでうまくユーザの行動がWallに流れればソーシャルに広がる仕組みを組み込めるのではないでしょうか。

今回の当初の実装上でAmazonやFacebookのAPIのレスポンスの遅さなどがあり、うまく動かない部分もありました。そのあたりの処理も一連のコミットに対応策があるのでご覧いただければと思います。

次回は、一旦Facebookから離れてこのようにアプリを運用する上でよく必要とされるHerokuのコマンドやアドオンなどを紹介します。

おすすめ記事

記事・ニュース一覧