knockoutjsでwebsocket-railsをつかった手順まとめ


# **概要**

knockoutjsでwebsocket-railsをつかったので、導入した手順と、つまづいた点を紹介します。

つくったのは、ユーザーに紐づくタスクリストの「追加・編集・削除・完了」みたいなのが全クライアントに反映されるやつです。

データ的には、以下の様な感じです。ユーザーは何人かいます。

```
user: [{
    id: 1,
    name: aaaa,
    todo: [
        {id: 1, name: aaaaaaa, del: 1},
        {id: 2, name: eeee, del: 1},
        {id: 3, name: ccccc, del: 0},
        {id: 4, name: hhhhh, del: 0},
        {id: 5, name: kkkkk, del: 0},
    ]
},
{
    id: 2,
    name: aaaa,
    todo: [
        {id: 6, name: jjj, del: 1},
        {id: 7, name: ee, del: 1},
        {id: 8, name: gggg, del: 0},
    ]
},
{
    id: 3,
    name: aaaa,
    todo: [
        {id: 9, name: aaaaaaa, del: 1},
        {id: 10, name: eeee, del: 1},
        {id: 11, name: ccccc, del: 0},
        {id: 12, name: hhhhh, del: 0},
    ]
}]
```

# **websocket-railsを導入する**

以下の記事を参考にしました。基本的には、手順通りやれば問題ないはずです。

* <a href="http://www.school.ctc-g.co.jp/columns/masuidrive/masuidrive14.html" target="_blank">WebSocketでサーバプッシュ ～Websocket-Rails～</a>
* <a href="http://washiiku.hatenablog.com/entry/2013/11/13/235027" target="_blank">RailsでWebSocketを使う</a>
* <a href="http://ithijikata.hatenablog.com/entry/2014/03/06/021948" target="_blank">websocket-railsでチャットもどき</a>

簡単にまとめると、以下の５手順で完了します。

1. websocket-railsのgemいれる
2. event.rbでコントローラーをマッピング
3. JSでマッピングしたルートにデータ送信
4. Railsで受け取り、すべてのクライアントに送信
5. JSでイベントをバインドし、受け取ったデータを好きに処理する


# **JS側で配列処理をする**

タスクをko.observableさせたいので、該当するデータを、しかるべき配列の中につっこまないといけません。ここが慣れていなかったので戸惑いました。以下ソースです。

### 削除の処理

```js
      // todo_destroyイベントを取得
      // dispatcherは「new WebSocketRails("ws://ホスト/websocket");」で、グローバルです。
      dispatcher.bind('todo_destroy', function (removedTodo) {

        $.each(view_model.users(), function() {
          this.todo.remove(function(item) { 

            // itemはobservableなのでitem.id()とする(http://qiita.com/okmttdhr/items/a180b96b5e5e1b30aa1c)
            // idが同じtodoを配列から削除

            return item.id() == removedTodo.id 
          });
        });

      });
```

### 編集の処理

完了もこれと同じような感じです。

```js
      // todo_updateイベントを取得
      dispatcher.bind('todo_update', function (updatedTodo) {
        $.each(view_model.users(), function() {

          // 更新の際はremoveのように便利なメソッドがないので(あったら教えて下さい)、eachをネストさせてusersのtodoの中身を見る。

          $.each(this.todo(), function(i, item) {

            // itemはobservableなのでitem.id()とする(http://qiita.com/okmttdhr/items/a180b96b5e5e1b30aa1c)
            // itemはobservableなのでitem.name(updatedTodo.name)のように更新する
            // idが同じtodoに対して更新

            if(item.id() == updatedTodo.id) item.name(updatedTodo.name);
          });
        });
      });
```

### 追加の処理

```js

      function TodoConf(data) {
          var self = this;
          self.id = ko.observable(data.id);
          self.name = ko.observable(data.user_id);
          self.del = ko.observable(data.completed);
      }

      // todo_createイベントを取得
      dispatcher.bind('todo_create', function (newTodo) {

        // pushしたデータもobservableにしたいので、生のデータを一度observableに変換する
        var newTodo = new TodoConf(newTodo);

        $.each(view_model.users(), function() {
          // user_idが同じuserに対してtodoを配列に追加
          if (this.id() == newTodo.user_id()) {
            this.todo.push(newTodo);
          };
        });
      });
```


# **まとめ**

knockoutjsっぽいことといえば、observableにするために配列どうするか考えたことくらいでしょうか。

websocketは案外難しくなく、リアルタイムでDOMをただしく反映するということの方が、複雑になればなるほど難しくなってゆくのかなと思いました。とりあえず、jQueryでやらなくてよかったです。。