カテゴリー:
Rails
タグ:
 Rails pjax ajax pushState

このエントリーをはてなブックマークに追加
更新日時:
2013年04月03日(水)
作成日時:
2013年02月17日(日)

前の記事 / 次の記事

目次

調べた時のRailsのバージョン: 3.2.11

  1. pjaxとは何か
  2. 何がいいのか
  3. Railsで動かすには?
  4. やったこと
  5. 追記:2013/02/26
  6. 追記:2013/04/03
  7. 参考ページ

1.pjaxとは何か

jQueryプラグインの名前。
pjaxが便利過ぎて鼻血出そうになった(railsのサンプル付き)が分かりやすかった。

何が出来るのかというと、ajaxのようにページ全体のリロードをすることなく、
部分的にビューを差し替えることが出来る。

ajaxに名前がクリソツだけどajax同列の何かではなくて
あくまでプラグインの名前っていうのが混乱の元な気がした。

2.何がいいのか

じゃあajaxでいいじゃん!!
って話になっちゃうのでajaxではイケてないけどpjaxを使うとイケてることがある。

何か?

URIが変わる。

URIが変わると何が良いのか?

例えばブログの記事等は一つの記事にはユニークなURIを割り当てたい。
"/articles/1" からajaxで遷移させた "/articles/2" のURIが "/articles/1" のままみたいなことを避けたい。

pjaxを使うとそれが出来る。

3.Railsで動かすには?

三つの方法を見つけた。

1.pjax_rails (gem) を使う
2.rack-pjax (gem) を使う
3.jquery-pjax (jquery plugin) を使う

結論から言うと3.jquery-pjaxでいいと思った。

1.の pjax_rails も2.の rack-pjax のいずれも
3.の jquery-pjax を簡単に扱えるようにするためのgemである。

が、jquery-pjax単体でも充分に使いやすいので素直にjquery-pjaxを直接使えばいいかなと。

ちなみに、
1.のpjax_railsは基本的に3.のjquery-pjaxを然るべき場所に配置してくれるだけのgemで、
2.のrack-railsはミドルウェアレベルでjquery-pjaxを扱えるようになるgem。

ミドルウェアレベルで使えると何が嬉しいのかというと、
1.のpjax_railsで導入した場合は小細工をしないとhtmlのタイトルの変更が出来ないが、
2.のrack-railsで導入した場合はhtmlのタイトルの変更も出来る。っていうことらしい。

けど単体で使った場合でもhtmlのタイトルの変更は簡単に出来るのでやっぱり単体で使えばいいかなと。

1.と2.については#294 Playing with PJAXを参考にした。
ただ、情報が古くてそのままだと使えないので、jquery-pjaxの説明も一緒に読まないと嵌まる。

4.やったこと

  1. jquery-pjaxを手に入れて然るべき場所に配置
  2. application.js のマニフェストjquery-pjaxを呼び出す
  3. ビューにpjaxをキックする要素とpjaxで置き換えられる要素を定義する
  4. 使用するコントローラーでリクエストがpjaxの時はレイアウトをレンダリングしないようにする
  5. 任意のjavascriptファイルにjquery-pjaxの動作を定義する

1.jquery-pjaxを手に入れて然るべき場所に配置

git clone してもコピー&ペーストでも何でもいいので、
jquery-pjaxの本体(jquery.pjax.js)を手に入れて app/assets/javascripts/ に配置する。

この場所に配置するのはマニフェストで //= require jquery.pjax として呼び出すためなのだけど、
この時、pjax_railsを使って入れた場合は、特に配置しなくても既に呼べる状態になっているので何もしなくていい。

2.application.js のマニフェストでjquery-pjaxを呼び出す

application.js にjquery.pjaxの行を追加(順序は重要)

vi app/assets/javascripts/application.js

//= require jquery
//= require jquery_ujs
//= require jquery.pjax
//= require_tree .

3.ビューにpjaxをキックする要素とpjaxで置き換えられる要素を定義する

pjaxによって差し替えられる情報を格納する要素と、pjaxによる差し替えをキックする要素を作成する。

まずレイアウト、

vi app/views/layouts/application.html.haml 

-# haml
%html
  %head
    -# JavaScriptが使えない場合はインスタンス変数からタイトルを取得するが、
    -# JavaScriptが使える場合はjquery-pjaxのコールバックでタイトルを置き換える(後述)。
    %title=@title
    =stylesheet_link_tag    "application", :media => "all"
    =javascript_include_tag "application"
    =csrf_meta_tags
  %body
    -# このコンテナーの中身をpjaxで変更する。
    %div#pjax-container
      =yield

次に個別のコンテンツ(=yieldの中身)

vi app/views/articles/show.html.haml

-# haml
%h1=@article.title
%p=@article.content
-# このリンクがクリックされると #pjax-container の中身が差し替えられる。
-# @article.next で次の記事を呼び出せるとする。
%p=link_to("次の記事", @article.next, :class => :pjax)

4.使用するコントローラーでリクエストがpjaxの時はレイアウトをレンダリングしないようにする

#pjax-container の中身を用意するコントローラのアクションに一行追加。

vi app/controllers/articles_controller.rb

def show
  略
  # pjaxのリクエストが来た時はレイアウトをレンダリングしない
  render :layout => false if request.headers['X-PJAX']
  略
end

※ これを書くようにって書いてあるんだけど、自分の環境だとなくても動くので無くてもいいのかも知れない。

5.任意のjavascriptファイルにjquery-pjaxの動作を定義する

次の行を追加

vi app/assets/javascripts/pjax.js.coffee

# coffee script
$ ->
  $(this).pjax('.pjax a', '#pjax-container').on('pjax:complete', ->
    $("title").text($("h1").text())
  )

何をしているのかというと、
まず pjax('.pjax a', '#pjax-container') の部分は、

pjax('pjaxによる差し替えをキックする要素', 'pjaxによって差し替えられる要素')

である。

この場合、".pjax"クラスを持つリンクがクリックされた時、
"#pjax-container"というIDを持つ要素の中身がリンク先の情報に差し替えられる、ということ。

次に、on('pjax:complete', -> $("title").text($("h1").text()) の部分はコールバックで、

on('このイベントが発生した時', 'この処理が行われる')

ここでは、pjaxリクエストが完了した時、h1要素が持つテキスト情報をhtmlのタイトルとして仕込むようにしている。
これでhtmlのタイトルの変更も出来る。

※ 最初勘違いしていたのだけど、
.on('pjax;complete', -> ) の部分はpjaxリクエストが完了した時は 常に発火 するもので、
$(this).pjax('.pjax a', '#pjax-container') をクリックした時に 限らない

なのでページの差し替えに成功した時だけhtmlのタイトルを差し替える場合は、次の通り。

# coffee script
$ ->
  $(this).pjax('.pjax a', '#pjax-container').on('pjax:success', ->
    $("title").text($("h1").text())
  )

クリックされた要素ごとにコールバックを書きたい場合は、$.pjax.click() 等を使って記述すれば書ける。
次のページに書いてある。jquery-pjax#pjaxclick

コールバックには pjax:complete の他にもいくつかあって、詳しくはjquery-pjax#ajax-relatedに書いてある。

5.追記:2013/02/26

基本的には

pjax('pjaxによる差し替えをキックする要素', 'pjaxによって差し替えられる要素')

で問題ないのだけど、差し替え対象の要素はレイアウトで yield される要素である必要がある様子。

-# haml
%html
  %head
    %title Index Page
  %body
    %div#content
      =yield

-# haml
%div#content-sub
  Nice to meet you.

の時、

$(this).pjax('a', '#content')

は出来るけど、

$(this).pjax('a', '#content-sub')

は出来ない。

6.追記:2013/04/03

pjaxは簡単に使えるし細かい設定も出来て便利なんだけど、
設定する項目が存在すること自体面倒くさいっていう理由で結局turbolinksを使っている。

7.参考ページ