AngularJSとRuby on Railsで作るCRUDアプリ – (4)Update

2014.04.12

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

前回構築したAngularJS+Ruby on Railsのアプリに
今回はCRUDの内のUpdate機能を実装し、ウィスキーの情報を更新する画面を作成しました。

画面遷移としては
・一覧画面(index.html.erb)よりリンクをクリックし、今回作成する更新画面(edit.html.erb)に遷移する
・更新画面でボタンを押下すると、AngularJSにより非同期でサーバを呼び出し、更新する
・登録後、AngularJSにより一覧画面に遷移する
となります。
flow

以下に、実装する上でのポイントとなる箇所を記述していきます。
尚、ソースコードは以下のGitHubに置いてあるので、全ソースを見たい方は参考にしてください。
AngularjsWhiskyList

実装について

1.ルーティング

更新画面に表示するデータを取得するためのURLとして、以下のコードをroutes.rbに追記します。

get 'whiskies/:id/detail' => 'whiskies#detail'

$ rake routes でルーティングの確認をすると、以下のようになります。

whiskies_list GET    /whiskies/list(.:format)       whiskies#list
              GET    /whiskies/:id/detail(.:format) whiskies#detail
(中略)
  edit_whisky GET    /whiskies/:id/edit(.:format)   whiskies#edit
       whisky GET    /whiskies/:id(.:format)        whiskies#show
              PATCH  /whiskies/:id(.:format)        whiskies#update
              PUT    /whiskies/:id(.:format)        whiskies#update
              DELETE /whiskies/:id(.:format)        whiskies#destroy

今回使用するのは
・更新画面に表示するデータを取得する「GET /whiskies/:id/detail(.:format) whiskies#detail」(2行目)
・更新画面に遷移するための「GET /whiskies/:id/edit(.:format) whiskies#edit」(4行目)
・更新データを送るための「PUT /whiskies/:id(.:format) whiskies#update」(7行目)
です。

2.一覧画面

一覧画面に、更新画面へ遷移するためのリンクと、削除するためのボタンを追加しました。
またTwitter Bootstrapのtableを使い、多少見栄えを良くしています。
(尚、今回は削除ボタンについては触れません)

index.html.erb
<h1>Whiskies#index</h1>
<%= link_to "new whisky", new_whisky_path, :class => 'btn btn-mini' %>
<table ng-controller="WhiskiesCtrl" class="table">
    <tr ng-repeat="whisky in data">
        <td>{{whisky.name}}</td>
        <td>${{whisky.price}}</td>
        <td><a href="/whiskies/{{whisky.id}}/edit" class="btn btn-mini">Edit</a></td>
        <td><button ng-click="Delete(whisky);" class="btn btn-mini">Delete</button></td>
    </tr>
</table>

EditリンクのURLの定義は「a href="/whiskies/{{whisky.id}}/edit」となっています。
{{whisky.id}}はAngularJSの式で、{{}}内に記述した変数やプロパティ等の値を参照します。
ここでは一覧に表示するデータのidが取得されるので、実際のURLは以下のような形となります。

/whiskies/2/edit

上記1.で記述した、更新画面に遷移するためのURLを指定していることが分かるかと思います。

3.更新画面

更新画面は以下のようになります。

edit.html.erb
<h1>Whiskies#edit</h1>
<div ng-controller="WhiskiesEditCtrl">
  <div>Name</div><div><input type="text" ng-model="data.name"></div>
  <div>Price</div><div><input type="text" ng-model="data.price"></div>
  <button ng-click='Update();' class="btn-primary">Update</button>
</div>

ここでは
・AngularJSの「WhiskiesEditCtrl」コントローラを呼び出す
・テキストボックスに「data.name」「data.price」を初期表示する
・Updateボタン押下時に「Update()」を呼び出す
を行っています。

4.更新処理のAngularJS

更新画面から呼び出されるAngularJSは、以下のようになります。

controllers.js
whiskiesListApp.controller('WhiskiesEditCtrl', function ($scope, $http, $window) {
    $http.get('detail').success(function(data) {
        $scope.data = data;
    }).error(function(data, status) {
        console.log('error:' + status);
    });

    $scope.Update = function(){
        $http.put('/whiskies/' + $scope.data.id, {'name': $scope.data.name, 'price': $scope.data.price}
        ).success(function(data, status, headers, config) {
            $window.location.href = '/';
        }).error(function(data, status) {
            console.log('error:' + status);
        });
    }
});

更新画面から呼び出される「WhiskiesEditCtrl」コントローラは
・「$http.get('detail').success(function(data) {・・・」のデータ取得処理
・「$scope.Update = function(){・・・」のUpdateボタン押下時の処理
の2つに分かれます。

「$http.get('detail').success(function(data) {・・・」のデータ取得処理は
上記1.で記述した、データを取得するURLを指定しています。

先に説明したように、更新画面自体は「/whiskies/:id/edit」の形で呼び出されています。
このURLの末尾「edit」を「detail」に変えることで、「/whiskies/:id/detail」となり
ルーティングで定義されているデータを取得するためのURLとなります。

「$scope.Update = function(){・・・」のUpdateボタン押下時の処理は
上記1.で記述した、更新データを送るためのURLを指定しています。

ここで注目して欲しいのは、「$http.put」でPUT送信している点です。
PUT送信することで、ルーティングで定義されているデータを更新するためのURLとなります。

※Railsのコントローラのdetail()、update()アクションについては
単純なActiveRecordのソースとなります。詳細はGitHub上のソースを参考にしてください。

最後に

以上です。
AngularJSの$httpオブジェクトを使うことで、Railsのルーティングに即したURLを生成し
処理を行うことができました。