AWDwR "Chapter18 The Web, V2.0"
今、巷で話題のWeb2.0ですよ!!
Intorducing AJAX
は、みんな知ってるからいいよね:-)。
The Rails Way
Railsには最初からAJAXのサポートが組み込まれているからWeb2.0もバッチリ。で、具体的に言うと
- prototype, effects, dragdrop, controlsのJavaScriptのライブラリが組み込まれている。
- JavascriptHelperというモジュールがある。
RailsでAJAXを使う場合は.rhtmlファイルのheadセクションで
<%= javascript_include_tag "prototype" %>
としておきましょう。レイアウトファイルのapplication.rhtmlに書いておけば全ページで使えるよ。
で、AJAXを使うための基本形はこんな感じ。
<%= link_to_remote("Do the Ajax thing", :update => 'mydiv', :url => {:action => :say_hello}) %> <div id="mydiv">This text will be changed</div>
このリンクをクリックするとサーバから返される文字列でdiv内の文字列を置き換える。div内を置き換える文字列にはレイアウトを適用したくない場合がよくあると思うけど、その場合はrender()の:layoutオプションにfalseを設定するか、アクションの先頭でlayout nilとしておきましょう。
POSTメソッドでAJAXのリクエストをしたい場合はこんな感じ。
<%= form_remote_tag(:update => "update_div", :url => {:action => :guess}) %>
一方、フォームの値が変更されたときに呼び出されるオブザーバというメソッドがあって、POSTされたデータはrequest.raw_postで参照可能。
<%= observe_field(:search, :frequency => 0.5, :update => :results, :url => {:action => :search}) %>
また、一定周期でAJAXのリクエストをするということもできる。
<%= periodically_call_remote(:update => "process-list", :url => {:action => :ps}, :frequency => 2) %>
The User Interface, Revisited
prototype.jsにはいろいろな機能があるので紹介するよ。まずはDOMマニピュレーション。
- $(id) 指定されたidのDOMエレメントを返す。
- Element.toggle(element, ...) 指定されたエレメントを表示するかどうかを切り替える。
- Element.show(element, ...) 指定されたエレメントを表示する。
- Element.hide(element, ...) 指定されたエレメントを非表示にする。
- Element.remove(element, ...) 指定されたエレメントをDOMから取り除く。
次に視覚効果。effects.jsが視覚効果のライブラリ。
1回きりの視覚効果にはこんなんがあって…
- Effect.Appear(element) 徐々に現れる。
- Effect.Fade(element) 徐々に消える。
- Effect.Highlight(element) Yellow Fade Techniqueを適用する。
- Effect.Puff(element) 煙の中に消える。
- Effect.Squish(element) 小さくなって消える。
何回も使える視覚効果にはこんなんがある。
- Effect.Scale(element, percent) 拡大、縮小する。
- Element.setContentZoom(element, percent)
Advanced Techniques
エレメントを置き換えるメソッドには以下のものがある。
- Insertion.Top(element, content) 先頭のエレメントの後ろに挿入する。
- Insertion.Bottom(element, content) 最後のエレメントの前に挿入する。
- Insertion.Before(element, content) 先頭のエレメントの前に挿入する。
- Insertion.After(element, content) 最後のエレメントの後に挿入する。
で、リクエスト時に発生するイベントのコールバックメソッドは以下のとおり。
- :loading() XMLHttpRequestがサーバにデータを送信し始める時に起動される。
- :loaded() XMLHttpRequestがサーバからのレスポンスを待っている時に起動される。
- :interactive() サーバからデータが返され始めたら起動される。これはブラウザ依存なので気をつけて。
- :complete() サーバからのレスポンスが完了したら起動される。
でも:loaded()と:interactive()はブラウザによって異なる動作をするのであまり使わない方がいいかもかも。
link_to_remote()のパラメタはこんな感じで…
- :confirm 確認のダイアログボックスを表示する。
- :before, :after リクエストする前/した後に評価するJavaScript。
requestオブジェクトのメソッドはこんな感じ。
- request.responseText サーバから返されるレスポンスのボディを返します。
- request.status サーバから返されるHTTPステータスコードを返します。
- request.getResponseHeader(name) サーバから返されるヘッダを返します。
プログレスインジケータは以下のようにすれば簡単に表示できる。
<%= text_field_tag :search %> <%= image_tag("indicator.gif", :id => 'search-indicator', :style => 'display:none') %> <%= observe_field("search", :update => :results, :url => {:action => :search}, :loading => "Element.show('search-indicator')", :complete => "Element.hide('search-indicato')") %>
ま、もっともtext_fieldのオートコンプレッションには最初からプログレスインジケータを表示する仕組みが組み込まれているけど。
<%= text_field(:items, :description, :remote_autocomplete => {:action => :autocomplete}, :indicator => "/path/to/image") %>
例えば同時に複数箇所を更新したい等複雑なことをしたかったら、サーバからJavaScriptを返して、それをクライアント側で評価するようにすればOK。
<%= link_to_remote("Update many", :complete => "eval(request.responseText)", :url => {:action => :update_many}) %>
ここまでのまとめとして、まずはAJAXを使わないTodo Listを作って、それからそれをAJAX対応にしてみたんだけど、詳しくは本を見てね:-)。
AJAXのテストをする場合はテスト用にXMLHttpRequestをシミュレートするxml_http_request()、略してxhr()というメソッドがあるよ。JavaScriptのインスペクションやデバッグをするにはFirefoxのVenkmanというアドオンが便利。
xhr :post, :index
request.xml_http_request?、略してrequest.xhr?というメソッドはprototypeライブラリから呼ばれた場合に真となるので、AJAXとして呼ばれたかどうかが判定できる。
link_to_remote()に:hrefというパラメタを設定しておくと、JavaScriptをオフにしているユーザに対して:hrefで指定したURLのリンクとして表示される。これはform_remote_tag()の場合は必要なくて、その場合はaction=が自動的に設定される。JavaScriptが有効かどうかでアクションを変えたい場合は:urlと:htmlの両方を設定しておきましょう。そうすればAJAXの場合は:url,そうじゃない場合は:htmlで指定したアクションがリクエストされるよ。
ありゃ、もうWeb V2.1だよ。AJAX周りは急速に変化しているのでRailsとそのAJAXサポートはよく見ておきましょう。これを書いている最中にも、オートコンプリートのテキストフィールド、進行状況を表示するファイルアップロード、ドラッグアンドドロップ、順序を入れ替えることができるリスト等々がサポートされ始めたよ。http://script.aculo.us/をチェキ!