Rails3.2 + pjax を使ってみた。+ pjaxでのgoogle adsense
kaeruspoon のデザイン変更とあわせてRails3.2.2化 + pjax対応をしてみました。
pjax対応は、ライブラリが用意されているので思いの外簡単です。今のところ、DHHがつくった pjax_railsと、Rackに組み込んで使う rack-pjaxが有名なようです。
pjax_railsの使い方は簡単です。READMEにあるとおりですが、まずGemfileで設定しておきます。
gem 'pjax_rails'
それから、app/assets/javascripts/application.jsにてjqueryの後くらいにpjaxを追加します。
//= require jquery
//= require jquery_ujs
//= require pjax
//= require_tree .
あとはviewsのlayoutの中で、yield :contentしている部分を
<div data-pjax-container>
でくくります。
<html>
...
<div data-pjax-container>
<%= yield %>
</div>
これで完了です。リンクをクリックすると、Railsはcontentのレンダリングだけを行ってレスポンスとして返します。ブラウザ側は受け取ったデータを、data-pjax-container内に差し替えます。
pjax_railsはとても簡単なのですが、デフォルトですべてのリンクがpjax化されたり、titleタグが変化しなかったりします。
kaeruspoonではrack-pjaxを使うことにしました。こちらは明示的にpjaxを行いたいリンクを指定できるのと、rack内で処理するためRailsの挙動は変わらなかったりするのでわかりやすいです。
具体的には、Railsは通常どおりlayoutまで含めてレンダリングしますが、Rack内でhpricotにより必要な部分を抜き出してレスポンスとします。このとき、titleタグもうまいことやってくれるので、コードの修正なしにtitleタグも差し替えることが可能です。
Gemfileに以下を追加します。
gem 'rack-pjax
Rack::PjaxをRackのミドルウェアに積みます。
config/application.rb
module Kaeruspoon
class Application < Rails::Application
config.middleware.use Rack::Pjax
....
end
end
jquery-pjaxを別途app/assets/javascriptsなどに配置しておきます。
それから、app/assets/javascripts/application.jsにてjqueryの後くらいにjquery-pjaxを追加します。
//= require jquery
//= require jquery_ujs
//= require jquery.pjax
//= require_tree .
pjax_railsと同様に差し替えを行いたい箇所を決定しておきます。同様にdata-pjax-containerタグとするなら、pageロード後に以下のようなjavascriptを実行するようにします。
$('a:not([data-remote]):not([data-behavior]):not([data-skip-pjax])').pjax('[data-pjax-container]')
ここで対象となるリンクが指定されます。kaeruspoonでは、
$(".pjax a").pjax('[data-pjax-container]');
というように、class名pjaxのDOM内のリンクを対象にするようにしました。
pjaxでコンテンツを差し替えすると、ブラウザのスクロール位置が変になることがあります(縦に長いページのあとに縦に短いページを呼んだときなど)。そのため、pjaxによる差し替えが成功したあとは、ページのトップにスクロールするようにしてみました。
$('[data-pjax-container]').on('pjax:success', function(){
$('html,body').animate({ scrollTop: 0 }, 'slow','swing');
articleLoaded();
});
このあたりのイベントハンドリングはjquery-pjaxでいろいろ定義されています。
pjaxを採用してひとつ問題になったのがgoogle adsenseです。adsense内でdocument.wrtie()などをコールしているため、古いブラウザなどだと広告だけが存在する白紙ページになってしまいます(最近のブラウザなら広告のほうが表示されないようになるみたい)。
javascriptで動的に表示を変更したページでのadsenseの表示方法がよくわかりませんでした。iframeを使うのは規約違反のようです。また、 ページロード後に外部スクリプトのdocument.writeを実行する方法の間違いを直すなどのようにdocument.write自体をオーバーライドする手法もありますが、こちらも規約違反になりそうです。
なので今回は、pjaxでの遷移先ではadsenseの表示を諦めました。
<% if params[:_pjax].blank? %>
...adsense表示
<% end %>
これでpjax以外の場合のみ、adsenseが表示されます。