QA@IT

pjaxでリクエストが2回発生してしまう

4035 PV

下記のようにpjaxを試用するプログラムを書いているのですが、pjaxを発生させるaタグをクリックした際に、2回リクエストが発生してしまっています。

1度目のリクエストではrequest.headers['X-PJAX']が"true"になっていますが、2度目のリクエストでrequest.headers['X-PJAX']がnilになり、通常のページ遷移となってしまっています。

何か原因と考えられるものはありますでしょうか?


Gemfile

# For pjax
gem "pjax_rails", "~> 0.3.4"

app/assets/javascripts/application.js

//= require jquery
//= require jquery-ui
//= require jquery_ujs
//= require jquery.pjax

$(function() {
  $("#main").pjax('a', { timeout: 30000 });
});

app/views/home/index.html.erb

<div id='main'>
  <a href='/home/pjax_test'>Test1</a><br />
</div>

app/controllers/home_controller.rb

  def pjax_test
    puts "[ ---------- request.xhr? ---------- ]" ; request.xhr?.tapp ;
    puts "[ ---------- request.headers['X-PJAX'] ---------- ]" ; request.headers['X-PJAX'].tapp ;
    if request.headers['X-PJAX'] == "true"
      render text: "pjax true" and return
    else
      render text: "pjax false" and return
    end
  end

ログ

[ ---------- request.xhr? ---------- ]
0
[ ---------- request.headers['X-PJAX'] ---------- ]
"true"


Started GET "/home/pjax_test?_pjax=%23main" for 127.0.0.1 at 2012-11-03 19:45:05 +0900
Processing by HomeController#pjax_test as HTML
  Parameters: {"_pjax"=>"#main"}
  User Load (0.8ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1 AND ("users"."deleted_at" IS NULL) LIMIT 1
  EXPLAIN (0.2ms)  EXPLAIN QUERY PLAN SELECT "users".* FROM "users" WHERE "users"."id" = 1 AND ("users"."deleted_at" IS NULL) LIMIT 1
EXPLAIN for: SELECT  "users".* FROM "users"  WHERE "users"."id" = 1 AND ("users"."deleted_at" IS NULL) LIMIT 1
0|0|TABLE users USING PRIMARY KEY

  Rendered text template (0.0ms)
Completed 200 OK in 20ms (Views: 6.0ms | ActiveRecord: 1.0ms)


Started GET "/assets/favicon.ico" for 127.0.0.1 at 2012-11-03 19:45:05 +0900
Served asset /favicon.ico - 304 Not Modified (0ms)
[ ---------- request.xhr? ---------- ]
nil
[ ---------- request.headers['X-PJAX'] ---------- ]
nil


Started GET "/home/pjax_test" for 127.0.0.1 at 2012-11-03 19:45:05 +0900
Processing by HomeController#pjax_test as HTML
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1 AND ("users"."deleted_at" IS NULL) LIMIT 1
  EXPLAIN (0.1ms)  EXPLAIN QUERY PLAN SELECT "users".* FROM "users" WHERE "users"."id" = 1 AND ("users"."deleted_at" IS NULL) LIMIT 1
EXPLAIN for: SELECT  "users".* FROM "users"  WHERE "users"."id" = 1 AND ("users"."deleted_at" IS NULL) LIMIT 1
0|0|TABLE users USING PRIMARY KEY

  Rendered text template (0.0ms)
Completed 200 OK in 12ms (Views: 0.8ms | ActiveRecord: 0.5ms)

回答

原因はサーバから返すコンテンツがタグで囲まれていないためです。
その場合 pjax 側で location を直接書き換えているので、2度目のアクセスが発生します。

以下にあるコードの、
https://github.com/defunkt/jquery-pjax/blob/master/jquery.pjax.js

次の部分で、コンテンツの要素数チェックをしています。
ここで要素数が0になると、コンテンツがないと判断して、locationReplace の呼び出しにつながります。

if ($body.length === 0)
  return obj

仕様は分かっていませんが、動作的にはそうなっているようです。
ひとまずの解決策は適当なタグで以下のように囲むことです。

render text: "<span>pjax true</span>" and return
編集 履歴 (0)
  • なるほど。ありがとうございます。ページ遷移をするなら要素が必ず含まれているべき、という感じなのでしょうか。。確かに仕様はちょっとよく分からないですね。。 -

サーバー側のログの時刻によるとタイムアウトで通常のリクエストをしなおしているというわけでもなさそうなので、
....pjax(...).on('pjax:error', function(event,xhr,status){ alert('ERROR: ' + xhr.status + ' ' + xhr.statusText); })
といった感じでクライアント側で何かエラーが起きていないか調べてみるとどうでしょうか。

編集 履歴 (0)
  • ありがとうございます。試してみます。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。