Facebook Comment Plugin と Rails Turbolinks の共存

Posted 7 months ago by yoosee.
  textfi rails

このブログでは Facebook Comment Plugin を使っているのだけど、割と頻繁にそれが表示されないということが起こっていた。少し調べるとどうも Rails4 の Turbolinks の影響らしい。Turbolinks は Rails でページ間遷移をした時にコンテンツを差分だけ部分更新することで読み込みをかなり早くするというありがたいものなのだが、その性質上、document.ready や on.(“page:load”), (“page:change”) などのイベントが食われてしまう。

fb-comment

対策としては jquery と turbolinks を共存させるための jquery-turbolinks というものがあるので取り敢えずそれを追加する。Gemfile に以下を追加。

gem 'jquery-turbolinks'

app/assets/javascripts/application.js に以下を追加。なお jquery の直後、turbolinks の手前に入れる必要がある。

//= require jquery
//= require jquery.turbolinks
...
//= require turbolinks
...

Google Site Search などはこれで直ったのだが、FB Comment Plugin ないし FB SDK の場合は明にイベントを読んであげないといけないらしい。 Turbolinks Compatibility with FacebookRails / Turbolinks を使いつつもフェイスブックの Page Plugin を設置する | Workabroad.jp を参考に、app/assets/javascripts/social.js.coffee を追加。当然 application.js には対応する //= require social.js を加えておく。

$ ->
  loadFacebookSDK()
  bindFacebookEvents() unless window.fbEventsBound
        console.log 'everytime'

bindFacebookEvents = ->
  $(document)
    .on('page:fetch', saveFacebookRoot)
    .on('page:change', restoreFacebookRoot)
    .on('page:load', ->
      FB?.XFBML.parse()
    )
  @fbEventsBound = true

saveFacebookRoot = ->
  if $('#fb-root').length
    @fbRoot = $('#fb-root').detach()

restoreFacebookRoot = ->
  if @fbRoot?
    if $('#fb-root').length
    @fbRoot = $('#fb-root').detach()

restoreFacebookRoot = ->
  if @fbRoot?
    if $('#fb-root').length
      $('#fb-root').replaceWith @fbRoot
    else
      $('body').append @fbRoot

loadFacebookSDK = ->
  window.fbAsyncInit = initializeFacebookSDK
  $.getScript("//connect.facebook.net/ja_JP/sdk.js#xfbml=1")

initializeFacebookSDK = ->
  FB.init
    version : 'v2.7'
    appId  : '1721451128113160'
    status : true
    cookie : true
    xfbml  : true

FB Comment Plugin で記載するように言われる下記は script 部分を全て消去。当該処理は上記にあるので。

<div id="fb-root"></div>
<script>
...
</script>

なお Facebook SDK and rails 4 Turbolinks - Stack Overflow の方法だとうまくいかなかった。document.ready や page:change, page:load 時に FB.init を呼ぶという動作は実質同じなはずなんだけど…。