レベル: 中級 Bruce Tate (bruce.tate@j2life.com), President, RapidRed
2006年 12月 05日 Web ページの対話性を高める技術、Ajax に対する熱狂が、さらに高まっています。また Ruby on Rails フレームワークの人気も高まっていますが、その理由の 1 つは Ajax と非常にうまく統合できるという強みがあるためです。Ajax on Rails が、なぜそれほど強力な組み合わせなのか、この記事で学びましょう。
前回と前々回の境界を越えるシリーズの記事 (「参考文献」を参照してください) では、Rails のアドオンである Streamlined を紹介しました。Streamlined は Rails という土台を効果的に利用して、単純な、Ajax 対応のユーザー・インターフェースを素早く生成します。今まで岩の下に隠れていた人でもない限り、皆さんは Ajax が XML とJavaScript、そして Web 標準を利用して、対話性が高い Web ページを作成するプログラミング手法であることは認識しているでしょう (そうした Web ページは、Google Maps やその他何百ものサイトに見られます) 。Streamlined に関する記事を読んだ人の何人かは、Ruby on Ajax on Rails の動作について説明するように私に求めてきました。この記事では、いくつかの単純な Ajax の例を取り上げ、そうした例をとおして、Ruby と Ajax との組み合わせがなぜそれほど素晴らしいかを説明します。このシリーズの次回の記事では、プログラミング言語としての JavaScript について掘り下げる予定です。
Ajax の定義
Ajax は、Asynchronous JavaScript + XML を表します。情報アーキテクトである Jesse James Garrett が 2005 年に、それまで10 年間ほど隙間を縫う手法として使われてきたこの技術を、こう名付けました (「参考文献」を参照してください)。その後 Ajax は爆発的に使われるようになり、同時にライブラリーや人気の Web サイト、記事なども増加してきました。
Ajax はブラウザーの基本的な使用モデルを再定義しており、一度に 1 ページを描画します。ブラウザーは Ajax によって、ページ更新の間にサーバーと通信することができます。利点としてユーザー・エクスペリエンスを豊かなものにできますが、複雑になるという犠牲を伴います。Ajax は、クライアントとサーバーとの間で、JavaScript のクライアント・サイド・ライブラリーを使って XML を送信することで動作します。Ajax 開発者はいつでもクライアントから非同期リクエストを送信できるため、サーバーがリクエストを処理する間、ユーザーとの対話動作を継続することができます。Ajax リクエストの流れは次のとおりです。
 |
このシリーズについて
この、境界を越えるシリーズでは、著者である Bruce Tate が、「今日の Java プログラマーは、他の手法や言語を学ぶことから多くを得ることができる」という概念を押し進めます。プログラミングの世界の様相は、あらゆる開発プロジェクトにとって Java が最善の選択肢であることが明確だった頃から変わってきています。他のフレームワークも Java フレームワークと同じ構築形態をとりつつあり、また他の言語での概念を学ぶことによって、それを Java プログラミングに生かすこともできます。皆さんが書く Python (あるいは Ruby や Smalltalk、その他何であれ) コードによって、皆さんの Java コーディングに対する取り組みも変わる可能性があるのです。
このシリーズでは、Java 開発とは大幅に異なりながら、同時に Java 開発にも直接応用できるプログラミング概念や手法について紹介します。場合によると、そうした技術を利用するためには、それらを統合する必要があるかも知れません。また場合によると、そうした概念は直接利用できるものかもしれません。他の言語やフレームワークが、開発者やフレームワーク、Java コミュニティーでの基本的な手法にまで与えうる影響に比べると、個々のツールはそれほど重要ではありません。
|
|
- ユーザーによるマウス・クリックやプログラミング・タイマーによるトリガーなどのイベントによって、JavaScript 関数が起動されます。
- その JavaScript 関数は、ページ全体に対するリクエストではなくページの一部に対するリクエストを作成します。そして JavaScript はそのリクエストを、HTTP を使って Web サーバーに送信します。
- この HTTP リクエストによって、サーバー上のスクリプト (Rails コントローラー・メソッドや Java™ サーブレットなど) が呼び出されます。
- サーバー・スクリプトは XML 文書を作成し、それをクライアントに返します。
- クライアントはリクエストの結果を受信すると、Web ページの一部 (リスト要素や div タグ、あるいは画像など) を非同期に作成、更新、あるいは削除します。
すべての Ajax アプリケーションは、上記の流れに似た手法を使います。例えば、辞書の単語と単語の定義を管理するアプリケーションを考えてみてください。古いスタイルのアプリケーションでは、ある定義を編集する場合に新しいページ・ビューを強制します。一方 Ajax では、インプレース編集が可能です。つまり定義テキストを入力フィールドで置き換え、そしてそのフォームを更新された定義で置き換えることができるのです。
Ajax ソリューションのコンポーネントは、次のようなものです。
- 非同期リクエストを扱うクライアント・サイドの JavaScript ライブラリー
- 着信したリクエストを処理し XML レスポンスを作成する、サーバー・サイド・ライブラリー
- リクエスト送信の結果として受信した XML を処理するクライアント・サイド・ライブラリー
- 既存の Web ページを更新できるようにするライブラリー (DOM (document object model) と呼ばれます)
- UI や統合に関する不可避の問題を処理するためのヘルパー・ルーチン
この、イベント、リクエスト、レスポンス、置き換え、というモデルは、大部分の Ajax アプリケーションのコアとなるモデルですが、Ajax を扱うのが初めての人は、利用可能なライブラリーの数や、それらの間の大きな違いに驚くかもしれません。業界には数多くの Ajax フレームワークがあり、その多くは重複しており、明確な勝者はいません。Java の市場だけでも、何十ものライブラリーが使われています (例えば、Echo や Dojo、DWR、GWT (Google Web Toolkit)、Java Web Parts、AjaxAnywhere、AjaxTags、Scriptaculous、そして Prototype など)。こうしたフレームワークは、それぞれまったく異なる手法を使っています。例えば GWT など一部のものは、JavaScript コードを生成する Java ライブラリーを提供することによって、すべての JavaScript を隠そうとします。またその他に、JavaScript を使いやすくしようとするものもあります。Dom4J のように非常に包括的なものがある一方、1 つの小さな問題をうまく解決しようとするものもあります。人気のある新技術にありがちな、この至るところにソリューションが存在している状況は、今後もしばらく整理が難しいと思われ、またデバッグ・ツールや、UI のプラクティス (「戻る」ボタンの扱いなど)、賢明な開発プラクティスなどは少しずつ具体化されていくでしょう。Java プラットフォームでの Ajax ライブラリーの強みは多様性ですが、それは弱点でもあります。多様性があるために、決定ができないこと、統合上の問題、複雑さなどが生じてくるからです。
Ruby on Rails の場合、2 つの理由から状況が劇的に異なります。第 1 に、Ruby on Rails には、コアとなる 1 つの Web 開発プラットフォーム、つまり Ruby on Rails があります。第 2 に、これまで Rails で行われた Ajax 開発作業の大部分は、Scriptaculous と Prototype (「参考文献」を参照してください) という 2 つのコア・フレームワークを中心に行われてきました。ランタイム・コード生成とカスタム・タグを使う Rails の手法では、JavaScript の複雑さからは切り離されるのです。では、実際にそれを確認してみましょう。毎度のことですが、この記事を読みながらコーディングもしたいのであれば、Rails をダウンロードする必要がありますが、これには必要な Ajax フレームワークが付属しています (「参考文献」を参照してください)。Rails 環境をこじ開け、私と一緒に中を覗いてみましょう。
Ajax を使わない単純な Rails アプリケーション
Rails と Ajax を使うために、空のプロジェクトを作成し、2 つのメソッドを持つコントローラーを生成します。1 つは単純なページをコントロールし、もう 1 つは Ajax レスポンスを設定します。下記のコマンドを入力します。
rails ajax
cd ajax
script/generate controller ajax show time
|
最初と 2 番目の行は Rails プロジェクトを生成し、そして新しいディレクトリーに切り替えます。3 番目の行は、ajax というコントローラーと、2 つのアクション (show と time) のビューを生成します。リスト 1 は、コントローラーのコードを示しています。
リスト 1. 2 つの空メソッドを持つコントローラー
class AjaxController < ApplicationController
def show
end
def time
end
end
|
最初に、Ajax を使わない 2 つの単純なビューを作成し、その 2 つを後から Ajax で結びつけます。app/views/ajax の show.rhtml ビューを編集し、リスト 2 のようにします。
リスト 2. 単純なビュー
<h1>Ajax show</h1>
Click this link to show the current <%= link_to "time", :action => "time" %>.
|
リスト 1 と 2 のコードには Ajax サポートが何も含まれていませんが、とにかくこれを細かく調べることにします。まず、リスト 1 のコントローラーを見てください。2 つの空のコントローラー・メソッドが、受信される HTTP リクエストを処理します。もし (render メソッドを使って) 明示的にビューを描画しないと、Rails は、メソッドと同じ名前を持つビューを描画します。Scriptaculous と Prototype のライブラリーは HTTP も使うため、Rails は標準の HTTP メソッドと Ajax メソッドとを区別する必要がありません。
今度は、リスト 2 のビューに注目しましょう。2 行目 (<%= link_to "time", :action => "time" %>) の link_to ヘルパーを除けば、大部分のコードは単純な HTML です。
これまでの境界を越えるシリーズの記事で見てきたとおり、Ruby は <%=h と %> の間にあるコードを、その式の値で置き換えます。この場合 link-to メソッドは、単純な HTML リンクを生成するヘルパーです。このリンクは、コードを実行すれば見ることができます。script/server と入力してサーバーを起動し、ブラウザーで http://localhost:3000/ajax/show を見ます。そうすると図 1 に示すようなビューが見えるはずです。
図 1. Ajax を使わない単純なユーザー・インターフェース
ブラウザーのメニュー・オプションをクリックして、ページのソースを表示させます(Internet Explorer では表示 > ソース、Firefox では表示 > ページのソース です)。そうすると、リスト 3 のコードが見えるはずです。
リスト 3. show.rhtml で生成されたビュー
<h1>Ajax show</h1>
Click this link to show the current <a href="/ajax/time">time</a>.
|
リスト 3 のリンクのコードに注目してください。Rails ユーザーは、テンプレートを使うことで、面倒で間違いやすい HTML 構文を扱わずにすみます。(Ajax コードも同じように動作します。つまりヘルパー・メソッドを使って、リモート・リクエストと HTML への置換を処理する JavaScript コードを追加するのです。) このリンクをクリックすると、time メソッドのデフォルト・ビューが表示されますが、私はまだそれを実装していません。これを修正するために、app/controllers/ajax_controller.rb の time メソッドを、リスト 4 のコードで置き換えます。簡単にするために、私はコントローラーから直接ビューを描画しています。後でこれを整理し、ビューを描画することにします。
リスト 4. time を描画する
def time
render_text "The current time is #{Time.now.to_s}"
end
|
これで、リンクをクリックすると、図 2 のビューが表示されるはずです。
図 2. Ajax を使わないビュー
この UI に問題があることは、すぐにわかると思います。2 つのビューが、別々のページに属していません。このアプリケーションは、リンクをクリックすると時間を示す、という 1 つの概念しか表現していません。時間を繰り返し更新するためには、その都度リンクをクリックしてから「戻る」ボタンをクリックしなければなりません。この問題は、リンクと時間を同じページに置くことで解決できるかもしれません。しかし show ページが非常に大きくなったり複雑になったりすると、ページ全体を再表示するのは無駄であり、また複雑になりすぎる可能性があります。
Ajax を追加する
Ajax を使うことで、Web ページの一部分のみを更新することができます。ほとんどの作業を、Rails ライブラリーが行ってくれます。このアプリケーションに Ajax を追加するためには、下記の 5 つを行う必要があります。
- JavaScript を使うように Rails を構成する。
- 単純に HTML リンクを描画するのではなく JavaScript の Ajax リクエストを送信するように、time リンクを変更する。
- 更新すべき HTML フラグメントを指定する。
- 更新された HTML のコンテンツのための場所を用意する
- コントローラー・メソッドと、場合によっては Ajax レスポンスを描画するビューを作成する。
まず、app/views/ajax/show.rhtml のコードをリスト 5 のように変更します。
リスト 5. show ビューを、Ajax を使うように変更する
<%= javascript_include_tag :defaults %>
<h1>Ajax show</h1>
Click this link to show the current
<%= link_to_remote "time",
:update => 'time_div',
:url => {:action => "time"} %>.<br/>
<div id='time_div'>
</div>
|
私はいくつかの変更を行いました。第 1 に、構成を処理するために、必要な JavaScript ライブラリーを直接、ビューの中に単純に含めました。通常は他にもビューがあるため、また繰り返しを避けるために、 JavaScript ファイルを共通の Rails コンポーネント (Rails レイアウトなど) の中に含めるようにしています。この例では 1 つのビューしかないため、そうしたことはせず、単純にしています。
第 2 に、link タグを、link_to_remote を使うように変更しました。このリンクが何をするのかについては、すぐ後で説明します。次の 3 つのパラメーターに注目してください。
- リンク・テキストは、Ajax を使わない場合と変わっていません。
- :update パラメーター。今までこの構文を見たことがない人は、:update => 'time_div' を名前付きパラメーターと考えてください (:update が名前で update_div が値です)。このコードは Prototype ライブラリーに対して、time_div という名前を持つ HTML 要素が、このリンクの結果によって更新されることを伝えています。
- :url => {:action => "time"} は、このリンクが呼び出す URL を指定します。:url は、ハッシュ・マップの値をとります。実際には、ハッシュ・マップにはコントローラー・アクション (:time) のための要素しかありません。理論的には、URL にはコントローラーの名前と、コントローラーが必要とする可能性のあるオプション・パラメーターも含めることができます。
リスト 5 を見ると、空の div もあることがわかります。Rails はこれを、現在の時間で更新します。
ブラウザーに、ページ http://localhost:3000/ajax/show をロードします。リンクをクリックすると、図3 のような結果が見えるはずです。
図 3. Ajax を使ったビュー
ここで何が起きているかを知るためには、この Web ページのソースを見るのが一番です。リスト 6 はそのコードを示しています。
リスト 6. Ajax に対応した、show テンプレートの結果
<script src="/javascripts/prototype.js?1159113688" type="text/javascript"></script>
<script src="/javascripts/effects.js?1159113688" type="text/javascript"></script>
<script src="/javascripts/dragdrop.js?1159113688" type="text/javascript"></script>
<script src="/javascripts/controls.js?1159113688" type="text/javascript"></script>
<script src="/javascripts/application.js?1159113688" type="text/javascript"></script>
<h1>Ajax show</h1>
Click this link to show the current
<a href="#" onclick="new Ajax.Updater(
'time_div', '/ajax/time', {asynchronous:true, evalScripts:true});
return false;">time</a>.<br/>
<div id='time_div'>
</div>
|
JavaScript インクルードのリストに注目してください。このリストは、Rails のヘルパー、include_javascript_tags :defaults が作ってくれたものです。次に、HTML リンクの代わりに、新しい Ajax.Updater オブジェクトを作成するための JavaScript 関数コールがあります。ご想像のとおり、asynchronous と呼ばれるパラメーターが真に設定されています。そして最後に、HTML の div タグがありますが、タグの中に値の指定はありません。これは最初のページで、div タグに値の指定がないためです。
他の Ajax オプションを使う
Ajax は、予想外の動作を含めて、強力な動作を生成することができます。例えばユーザーは、time リンクが更新されていることに気が付かないかもしれません。そうした場合に link_to_remote オプションを使うと、(ユーザーが気付くように) この項目に特殊な効果を持たせることができます。そうした効果のいくつかを適用してみましょう。show.rhtml の link_to_remote ヘルパーを、リスト 7 のようなものに変更します。
リスト 7. 効果を追加する
<%= link_to_remote "time",
:update => 'time_div',
:url => {:action => "time"},
:complete => "new Effect.Highlight('time_div')" %>
|
Ajax による効果を工夫すれば、変更に対して一時的に注目させることはできますが、永遠に注目させることはできません。皆さんの目標は、ユーザーに対して、ユーザーの作業フローを妨害せずに変更を知らせることです。こうした薄い黄色による強調や、横から滑り込んでくるコンテンツ、フェードアウトするコンテンツであれば、ユーザーを永遠に妨害することはありません。
ここまで見てきたトリガーは、リンクのみですが、Ajax では、他にもいくつかのトリガーが使えます。そのいくつかはユーザーよって駆動され、またいくつかはプログラムによるイベント (タイマーなど) によって駆動されます。時計のようなものは、必ずしもユーザーの介在を必要としません。Ajax で periodically_call_remote メソッドを使うと、タイマーを周期的に更新することができます。show.rhtml のコードを編集し、リスト 8 のようにします。
リスト 8. リモート・メソッドを周期的にコールする
<%= javascript_include_tag :defaults %>
<h1>Ajax show</h1>
<%= periodically_call_remote :update => 'time_div',
:url => {:action => "time"},
:frequency => 1.0 %>
<div id='time_div'>
</div>
|
図 4 は、その結果を示しています。これは、ユーザーの操作を必要とせずに 1 秒間隔で更新する時計です。
図 4. Ajax を使って周期的に更新する時計
Rails ビューのコードは Ajax を使わない場合と似ていますが、その基礎となるコードは大きく異なっています。このバージョンでは、HTML ではなく JavaScript を使っています。ブラウザーでソースを表示させると、リスト 9 のコードが見えるはずです。
リスト 9. periodically_call_remote のソース
<script src="/javascripts/prototype.js?1159113688" type="text/javascript"></script>
<script src="/javascripts/effects.js?1159113688" type="text/javascript"></script>
<script src="/javascripts/dragdrop.js?1159113688" type="text/javascript"></script>
<script src="/javascripts/controls.js?1159113688" type="text/javascript"></script>
<script src="/javascripts/application.js?1159113688" type="text/javascript"></script>
<h1>Ajax show</h1>
<script type="text/javascript">
//<![CDATA[
new PeriodicalExecuter(function() {new Ajax.Updater(
'time_div', '/ajax/time', {asynchronous:true, evalScripts:true})}, 1.0)
//]]>
</script>
<div id='time_div'>
</div>
|
ここで何が起きているか、よく注意してください。小さなカスタム JavaScript フラグメントを操作するのではなく、実質的により上位の抽象化レベルで作業しており、また Ruby on Rails のテンプレート・システムによって、使用モデルが非常に自然に感じられるのです。
先ほど触れたとおり、私はコントローラーからテキストを直接描画しています。こうした単純化は最初は便利なのですが、長期間の使用には耐えません。私のビューはプレゼンテーションを処理する必要があり、またコントローラーは、ビューとモデルの間のデータを整理しなければなりません。この設計手法 (MVC (model-view-controller) と呼ばれます) によって、ビューあるいはモデルへの変更を容易に分離することができます。このMVC を実際に適用するために、単純に Rails にデフォルト・ビューを描画させます。そうすると、ご想像のとおり、それまでの time-div の内容は新しい内容で置き換わります。app/controllers/ajax_controller.rb の time メソッドを、リスト 10 のコードのように変更します。
リスト 10. リファクタリング
def time
@time = Time.now
end
|
app/views/ajax/time.rhtml のビューを、リスト 11 のように変更します。
リスト 11. ビューを使って Ajax コンテンツを描画する
<p>The current time is <%=h @time %></p>
|
コントローラー・メソッドは、@time と呼ばれるインスタンス変数を設定します。コントローラーは何も明示的に描画しないため、Rails は time.rhtml ビューを描画します。この使用モデルは、Ajax を使わずにビューを描画する場合と、まったく同じです。この場合も、Rails によって、開発者は Ajax を使うアプリケーションと使わないアプリケーションとの間の違いを意識する必要がなくなることがわかります。従来の Web アプリケーションと Ajax との間で、使用モデルは驚くほど似ているのです。Ajax を利用する Rails アプリケーションが増えているのは、そのためのコストが非常に低いからです。
Ajax on Rails の、他の使い方
Ajax on Rails の使い方は幅が広く、奥も深いものです。1 本の記事、あるいは連載記事であっても、そのすべてを網羅することはできません。幸いなことに、Rails の Ajax サポートによって、他のいくつかの問題も解決されるのです。Ajax on Rails の一般的な使い方として、下記をあげることができます。
-
リモート・フォームの送信。Ajax on Rails フォームは、従来のフォームとまったく同じように動作しますが、非同期に送信する必要があります。これはつまり、Rails での Forms ヘルパー・タグは更新すべき URL を指定できるようになっている必要があり、また (link_to_remote で行ったように) 視覚効果を実行できる必要があります。Rails の submit_to_remote は、link-to-remote が link_to ヘルパーを拡張するのとまったく同じように、Rails の submit ヘルパーを拡張します。
-
複雑なスクリプトの実行。Rails 開発者は、複雑なスクリプトを実行しなければならないことがよくあります (単純に 1 つの div を更新して効果を実行する以上のことをする、など)。Rail では、このために JavaScript テンプレートが提供されています。JavaScript テンプレートを利用することによって、任意の JavaScript を、Ajax リクエストの結果として実行することができます。こうしたテンプレート (RJS テンプレートと呼ばれます) の一般的な使い方としては、1 つ以上の div の更新、フォーム検証の処理、また Ajax エラー・シナリオの処理などがあります。
-
補完。データベースの中の項目に基づいて、ユーザーに補完機能を提供したいことがよくあります。例えば、もしユーザーが Bru と入力したら、アプリケーションがデータベースの中にある「Bruce Tate」という値に気付くようにしたいものです。Ajax を使えば、あるフィールドの変化を周期的にチェックし、ユーザーが入力するごとに補完候補の提案することができます。
-
複雑なフォームの動的な構築。ビジネスの場では、ユーザーがどのフィールドを入力すべきかを知る前に、完成したフォームの一部分を見る必要がある、ということがよくあります。例えば (アメリカの) 税金申告書フォーム1040EZ は、ある種の収入や支出があるユーザーにとっては無効です。Ajax を使えば、作業を進めながらフォームを更新することができます。
-
ドラッグ・アンド・ドロップ。Rails では、他の多くのフレームワークで要求されるような手間をかけなくても、簡単にドラッグ・アンド・ドロップを実装することができます。

 |
まとめ
Ajax に問題がないわけではありません。うまくいく場合には、息をのむような効果が得られます。しかしうまくいかない場合には、デバッグがまったく別次元の作業となり、デバッグの手法やツールは、とても他の言語に匹敵するレベルに達していません。Ruby on Rails には大きな利点があります。それは単純さです。Rails ラッパーと素晴らしいコミュニティー・サポートのおかげで、ごくわずかの初期投資のみで、この新しい世界に容易に入り込むことができます。しかし Rails で実現できることは、そこまでです。Ajax という連続体の全体には広がらない 2 つのフレームワークでは、すべてのユーザーを満足することはできません。
Java 言語の場合には、Ajax のフレームワークや手法に関して、ずっと幅広い選択肢があります。柔軟さにも富み、また、素晴らしいサポート・ベースもあります。しかし柔軟さにはかなりの代償が伴います。強力な Ajax フレームワークを選ぶ必要があるだけではなく、Web 開発フレームワークも選ばなければなりません。例えば、JSF フレームワークを統合するための作業は、Struts を統合する場合と劇的に異なります。新しい技術は、単純さを要求することが多いものです。Ajax on Rails は、UI に Ajax の洗練された部分が必要な問題に対して、単純な答えとなるかもしれません。そうした問題は、Java 言語による高度なエンタープライズ統合機能では対応できないかもしれないのです。次回は、JavaScript を詳しく探ることにします。それまで、境界を越え続けていてください。
参考文献 学ぶために
製品や技術を入手するために
- オープンソースの Web フレームワーク、Ruby on Rails をダウンロードしてください。
-
Ruby プロジェクトの Web サイトから Ruby を入手してください。
議論するために
著者について  | 
|  | Bruce Tateは父であり、マウンテンバイク乗りであり、カヤック乗りであり、そしてテキサス州オースチンに住んでいます。Joltを受賞した『Better, Faster, Lighter Java』を含め、ベストセラーとなった3冊の著書を執筆しています。最近、『Spring: A Developer's Notebook』を発刊しました。彼はIBMに13年間在籍した後、J2Life, LLC社を設立し、Java技術とRubyに基づく軽量開発戦略とアーキテクチャーを専門としたコンサルティングを行っています。 |
記事の評価
|