QA@IT

jQuery Mobileで新規レコードが一覧に表示されないのはなぜ?

3466 PV

jQuery Mobileをビューに使ったカンタンなRailsアプリを作りました。シンプルなCRUDアプリです。ちゃんと動いているのですが、レコードを新規作成して show から index に戻ると、その追加したレコードが一覧画面に表示されません。リロードすると正しく表示されます。なので、サーバ側の動作は問題なさそうです。

indexのビューは、

%div{data: {role: 'header'}}
  %h1 Swim record
  = link_to 'Month', stats_path, data: {icon: 'grid'}, class: 'ui-btn-left'
  = link_to 'Add', new_swim_path, data: {icon: 'plus'}, class: 'ui-btn-right'

%div{data: {role: 'content'}}
  %ul{data: {role: 'listview'}}
    - @swims.each do |swim|
      %li
        = link_to "#{swim.swam_at}  #{swim.length}m", swim
        = link_to 'edit', edit_swim_path(swim), data: {icon: 'gear'}

などととなっていて、新規レコード作成の new.html.hamlは、

%div{data: {role: 'header'}}
  %h1 New entry
  = link_to 'Home', root_path, data: {icon: "home"}, class: "ui-btn-right"

%div{data: {role: 'content'}}
  = render 'form'

のようになっています。新規レコード作成後は、show にリダイレクトされて正しくレコードが作成されているのが表示されます。

jQuery Mobileでは、なるべくサーバへの通信を行わない設計になっているので、そもそも画面遷移していなくてAjaxでページ履歴を管理しているのですよね。その辺の問題だという気がするのですが、こういう場合は、普通どうやるのが正しいのか、ちょっと分かりません。ご存知の方がいらっしゃったら教えて下さいませ。

回答

RubyはまったくわからないのでjQuery Mobileの挙動に限って回答します。
jQuery Mobileでは、直前のページはDOMツリー内にキャッシュとして保持するのが、デフォルトの動作になっています。そのため、以下のような流れを考えた場合、

index→show→index

2回目のindexは、最初に表示したindexと同じものになります。つまり、ブラウザの「戻る」と同じ状況と想定しているわけですね。そのため、毎回新規に表示する場合には、次のようにキャッシュを削除するスクリプトを書くしかありません。

<div data-role="page" class="no-cache">
  <!-- ページ -->
</div>
$(document).on('pagehide', '.no-cache', function(){
   $(this).remove(); 
});

ちなみに蛇足ですが、ブラウザの「戻る」または、history.back()に関連する動作では、

index→show→index(ブラウザの戻る)→show

上記のルートでは、何もしなくてもshowは最新のものになります。ブラウザの戻るをした時点で、showのキャッシュは削除されます。このように「戻る」と通常のリンクでは、挙動の差異があるので覚えておくと良いと思います。参考までに、jQuery Mobileでは、以下のマークアップでhistory.back()と同じ動作を記述できます。

<a href="#" data-rel="back">...</a>
編集 履歴 (0)
  • yoshikawa_tさん、解説ありがとうございます。DOMツリーにぶら下がってるのですね。この辺のところをキチンと理解せずに使っていると、もっとハマることになりそうです。もう少し調べてみます。戻るの挙動の説明もありがとうございます。参考になります! -

JQMの規定動作だと、部分しか読まないし、しかも徹底的にキャッシュを効かせます。
Ajaxそのものがキャッシュを駆使するのに、その上にjQueryが動作し、さらにJQMがデフォルトで
全動作をAjax化しているため、JQMだけの責任ではないですが。
クライアントおよびサーバキャッシュを徹底的に切り、さらに不都合があればJQMのAjax動作を停めるかしか方策はありません。
たそれをすると、JQMがただのCSS Themeエンジンになってしまうことが悲しいです。。

編集 履歴 (0)
  • ありがとうございます。確かにあの遷移なしの「アプリ感」が損なわれるのは、ちょっと悲しいですね。うーん -

問題があるのは show → index の遷移だったりするので、ちょっとハッキッシュなのかもしれませんが、URLにダミーのパラメータを渡すことで、キャッシュではなく、サーバからデータを取ってこさせるようにしたら上手く行きました。

show.html.haml で、以下のように ?refresh=true を渡すという方法です。

%div{data: {role: 'header'}}
  %h1 Swim record
  = link_to 'Back', :back, data: {icon: "arrow-l"}, class: "ui-btn-left"
  = link_to 'Home', root_path + "?refresh=true", data: {icon: "home"}, class: "ui-btn-right"

レコード変更の影響をステートとして持っておいて、それが影響しそうなビューでは、同様にサーバ側に取りに行くようなことをするのが正解なのでしょうか。jQuery Mobileとして仕組みがあって良さそうに思えたりもしますが、うーん。

【追記】
リンクに data-ajax="false" を指定すると Ajax をオフにできるので、

%div{data: {role: 'header'}}
  %h1 Swim record
  = link_to 'Back', :back, data: {icon: "arrow-l"}, class: "ui-btn-left"
  = link_to 'Home', root_path, data: {icon: "home", ajax: false}, class: "ui-btn-right"

でも解決しました。こちらが正解ですね。kompiroさん情報ありがとうございます。

jQuery Moibleのリンクと遷移の話は、 http://jquerymobile.com/test/docs/pages/page-links.html に書いてありました。

編集 履歴 (1)
  • 特定のリンクだけajaxをオフにするのであれば、data-ajax="false"を指定できます。 -
  • kompriroさん、これが私がやりたかったことです。マニュアル読めよという感じですね、ありがとうございました。頂いた情報を回答に追記しました -
ウォッチ

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