RESTful APIとしてのRailsとクライアントとしてのJavaScript


[RailsにおけるRESTfulなURL設計勉強会 千駄ヶ谷.rb #12 #sendagayarb](http://www.zusaar.com/event/324057) にて発表予定の記事です。


# よくあるAjaxを利用したページの例

Sedndagaya.rbというグループへ投稿出来るサイトがあるとします。
この時、グループのページにアクセスすると、グループの詳細情報と、グループへ投稿された記事が表示されます。

このとき、大きく分けて3つの描写が行われます。

* 通常のリクエストに対するレスポンスの描写
* 非同期のリクエストに対するレスポンスの描写
* DOM要素のイベントに対するレスポンスの描写


その時の流れは以下のようになります。

1. エンドユーザーがあるURIをブラウザ経由でアクセスする。
たとえば、 ```http://example.com/groups/1``` にHTTP GETリクエストを送信してアクセスする。
1. Webサーバー(アプリケーション・サーバー)が対応するHTMLを返す。この例の場合、 ```/groups/1``` に対応するリソースを返す。
1. ブラウザがHTMLをレンダリングする。これが1つ目の**通常のリクエストに対するレスポンスの描写**となる。 
![group0](http://ppworks.github.com/images/shared/2012-07-23_restful_study/group_0.png)
1. この時、グループに投稿された記事を非同期に取得する。非同期に取得した記事は以下のように、インジケーターが表示されている部分へ差し込まれる。
![group0](http://ppworks.github.com/images/shared/2012-07-23_restful_study/group_1.png)
1. パスが ```/groups/1``` の場合、特定の ```JavaScript``` が実行されるようにしておく。
1. その ```JavaScript``` が ```/groups/1``` に関連するリソースを非同期のHTTP GETリクエストを送信し、その結果をHTML内の特定のDOM要素へ差し込む。これが2つ目の**非同期のHTTP GETリクエストに対するレスポンスの描写**
![group0](http://ppworks.github.com/images/shared/2012-07-23_restful_study/group_3.png)
1. 他にもレンダリングされたHTMLに含まれるUIにイベントを付与する。
![group0](http://ppworks.github.com/images/shared/2012-07-23_restful_study/group_4.png)
1. 例えば、 ```[このグループに投稿する]``` というボタンをクリックすると以下のように投稿フォームを表示する。これが3つ目の**DOM要素のイベントに対するレスポンスの描写**
![group0](http://ppworks.github.com/images/shared/2012-07-23_restful_study/group_5.png)


# 更に？

先の例では、GETリクエストによるリソースの取得のみを行いました。更に、以下のようにグループへ記事を投稿する処理も考えてみましょう。

![group0](http://ppworks.github.com/images/shared/2012-07-23_restful_study/group_7.png)

1. ```[投稿する]``` というボタンをクリックするとグループに紐付いた投稿を作成する。
1. ```/group/1/posts``` へHTTP POSTリクエストを送信する
1. リクエスト終了後は複数の処理が ```javascript``` により実行される。
	* フォームを閉じる
	* 投稿のフィードバックを表示する
	* 作成された記事をHTMLに挿入する
![group0](http://ppworks.github.com/images/shared/2012-07-23_restful_study/group_8.png)

# 必要なHTTPメソッドと対応するURIを洗い出してみる

RESTfulに作っておくと、```backbone.js``` など標準的な ```JavaScriptフレームワーク``` と連携しやすいです。

例えば以下のURIはRESTfulの指向で考えると統一されたインターフェースから導けば良いので、簡単に定義可能です。ここで言う統一されたインターフェースとはRailsにおけるRESTfulです。

* GET ```http://example.com/groups/1```
* GET ```http://example.com/groups/1/posts```
* POST ```http://example.com/groups/1/post```
* GET ```http://example.com/groups/new```

# JavaScriptの重要性

このように、通常のHTTP GETリクエストの処理と合わせた非同期処理を行う際に ```JavaScript``` は必須となります。

この```JavaScript``` をどこにどのように書くかが大事です。


## JavaScriptの実行Routing

先の例のように通常のHTTPリクエストの後に、

* 非同期のHTTPリクエストを行いたい
* 特定のDOM要素のイベントをハンドリングしたい

といった要件は、通常URIごとに異なります。

その時に、現在ブラウザが指し示しているURIでは関係ない```JavaScript```が全て同じ所に記載されているのはメンテナスがしづらいです。

```ひとつの.jsファイルに全部書く例
$(function() {
	// user pageで使います
	$('.user a.follow').click(function(e) {
		e.preventDefault();
		// ajaxでフォロー処理をします
	});

	// イベントの検索ページで使います。
	$('form.event_search input[type="text"]').click(function(e) {
		e.preventDefault();
		// 検索時の処理
	});

	// グループページで使います。
	$('.group a.new_post').click(function(e) {
		e.preventDefault();
		// グループに投稿する記事フォームを表示
	}):

	// … とにかく続く
	// ウゲェ
});
```

* たまたま```JavaScript``` の制御に利用するclass名やid名を追加したり削除したりすると悲惨
* そのページに関係ある処理とそうでない処理が分かりづらい

### たまたま```JavaScript``` の制御に利用するclass名やid名を追加したり削除したりすると悲惨

デザイナーさんとの協業時に発生しそうです。これは、デザイナーさんとclass名、id名などのルール決めをするか、```JavaScript``` 側では ```HTML5```
 の ```data-xxxx``` attributeを利用することで回避できそうです。HTML内に```data-xxxx```が溢れることになります。

```
<form data-name="event_search">
<!--　〜〜〜 -->
</form>
```

```
$('form[data-name="event_search"] input[type="text"]').click(function(e) {
	e.preventDefault();
	// 検索時の処理
});
```

### そのページに関係ある処理とそうでない処理が分かりづらい

[複数ページの window.onload をまとめて書ける jQuery プラグインを書きました](http://blog.kaihatsubu.com/?p=1735)という記事が良いです。この中に出てくる[jQuery-Router](https://github.com/tanabe/jQuery-Router)の例を示します。

```
$.route(
	{
		path: /\/users/,
		func: function() {
			$('.user a.follow').click(function(e) {
				e.preventDefault();
				// ajaxでフォロー処理をします
			});
		}
	},
	{
		path: /\/events/,
		func: function() {
			$('form.event_search input[type="text"]').click(function(e) {
				e.preventDefault();
				// 検索時の処理
			});
		}
	},
	{
		path: /\/groups/,
		func: function() {
			$('.group a.new_post').click(function(e) {
				e.preventDefault();
			});
		}
	},
);
```

どのページでどの ```javascript``` が実行されるかが分かりやすくなりました。ネストが深くなるので、Classで分けるなどの工夫をすると良いですね。


なお、手前味噌ですがrailsで言うパス内の ```/groups/:id``` といった ```params``` を参照できるようにしたバージョンは、[jQuery-Router](https://github.com/ppworks/jQuery-Router)からどうぞ。

## *.js.erb

例えば、```/groups/:id/posts``` への非同期のHTTP GETアクセス時にの ```JavaScript``` 処理を、```app/views/posts.js.erb``` に直接書く方法もあります。

この方法は、```JavaScript``` の記述が```app/assets/javascripts/*``` と ```app/views/*.js.erb``` に散らばり見通しが悪くなるので、あまりおすすめしません。

## JavaScriptのMVCの利用

* ```backbone.js```
* ```spine.js```

などが有名どころです。

### backbone.js

* model: resourceの操作をRESTfulに管理する
* collection: resource**s**の操作をRESTfulに管理する
* router: どのURIで何をするかを管理する
* view: どのDOM要素で何をするかを管理する

詳しくは、[qiitaのbackbone.jsでの検索結果](http://qiita.com/search?utf8=✓&q=backbone.js)を確認しましょう。

# まとめ

このように通常のHTTPリクエストと、非同期のHTTPリクエストの組み合わせのページを作ることが多い昨今、RESTful APIとしてのRailsとクライアントとしてのJavaScriptとの関係をどう記載するのかが重要となってきています。

その際、通常のHTTPリクエストと非同期HTTPリクエストを同じ統一インターフェースであるRESTfulな設計で管理すると一貫性が出て開発効率の向上につながると考えています。