実践入門 Ember.js

第7回データの永続化(Ember Data)

前回はショッピングカートを作成しつつ、Ember.jsの汎用的な機能を解説しました。今回は、Ember.jsの永続化層を扱うためのライブラリであるEmber Dataを解説します。

Ember DataはEmber.jsとは別のライブラリですが、Ember.jsのコアチームによって開発されている公式ライブラリです。ただ、APIがまだ安定しきっておらず今後変更される可能性があるため本稿執筆時点ではベータ版という位置付けです。

まだ発展途上のライブラリですが、サーバのデータをクライアントサイトで変更して保存する場合や既存のAPIに対してのクライアントをEmber.jsで作成する場合に大活躍するため、本連載でも取り扱うことにします[1]⁠。

環境準備

まずは環境準備です。前回の記事を参考に必要なファイルを準備してください。また、今回はこれに加えてEmber Dataを読み込む必要があります。Ember.js公式サイトのベータ版のダウンロードページからEmber Dataをダウンロードして、HTMLに読み込み用のscriptタグをを追加します。

本稿での対象バージョンはこちらです。

準備ができたらHTMLをブラウザで表示してください。ブラウザの開発者コンソールにEmber Dataのバージョンが表示されていれば準備完了です。

DEBUG: -------------------------------
DEBUG: Ember      : 1.10.0
DEBUG: Ember Data : 1.0.0-beta.15
DEBUG: jQuery     : 2.1.3
DEBUG: -------------------------------

それでは実際にEmber Dataに触れてみましょう。

データを扱う

DS.Model

Ember Dataでデータを扱う際はDS.Modelを継承したクラスを作成します。まずはブログ記事を表すPostと、記事に対してのコメントを表すCommentを作成しましょう。

App.Post = DS.Model.extend({
  title: DS.attr('string'),
  body: DS.attr('string'),

  comments: DS.hasMany('comment')
});

App.Comment = DS.Model.extend({
  text: DS.attr('string'),

  post: DS.belongsTo('post')
});

データとモデルの対応付け

データと対応させたいプロパティにはDS.attr()を指定します。こうすることで、データとモデルのプロパティがマッピングが必要であることをEmber Dataに知らせています。

型変換

DS.attr()の引数に形名を指定すると、JSONとして渡ってくるデータをモデルにマッピングする際に自動で型変換が行われます。利用可能な値は次の4つです[2]⁠。

  • string
  • number
  • boolean
  • date

特にJSONで表現できない日付Date型を扱いたい場合はdateを指定してください。データの型変換が不要な場合(特に、配列やオブジェクトを扱いたい場合)には引数は省略できます。引数を省略した場合、型変換は行われずデータとして渡された値がそのままモデルのプロパティに設定されます。

データの形式

この例では、データは次のような形式であることを想定しています。

// post
{
  "id": ...,
  "title": ...,
  "body": ...
}

// comment
{
  "id": ...,
  "text": ...
}

このデータのプロパティのうち"id"は自動でマッピングされるため、それ以外のプロパティにDS.attr()を指定します。

また、モデルを作成する際にはモデル同士の関連を指定できます。今回の例ではDS.hasMany()DS.belongsTo()を使って一対多の関連を定義しました。DS.hasMany()/DS.belongsTo()の引数には、モデル名を与えます。モデル名はモデルのクラスを小文字にしてハイフン区切りにしたものです。

クラス モデル名
Post post
Comment comment
TopicCategory topic-category

このモデル名は、関連の指定以外にもあらゆる場面で利用します。

次はデータを読み込む部分を解説します。

DS.Store

Ember Dataでは、REST APIなどから取得したデータはモデルにマッピングされDS.Storeによって管理されます。DS.Storeはクライアントサイドのデータベースのようなもので、取得したデータはこのストアにキャッシュされます。

外部サーバからデータを取得する方法は後述するので、まずここでは手元でデータを用意する方法を解説します[3]⁠。

App.ApplicationRoute = Ember.Route.extend({
  beforeModel: function() {
    this.store.push('post', {
      id: 1,
      title: 'はじめての Ember.js',
      body: 'これから Ember.js を始めようという方向けの記事です。'
    });

    this.store.push('post', {
      id: 2,
      title: '公式サイトの歩き方',
      body: 'http://emberjs.com/ の解説です。'
    });

    this.store.push('comment', {
      id: 1,
      text: 'はじめまして',
      post: 1
    });

    this.store.push('comment', {
      id: 2,
      text: '入門しました。',
      post: 1
    });

    this.store.push('comment', {
      id: 3,
      text: '詳しい説明を知りたいときはまず参考にします。',
      post: 2
    });
  }
});

では、DS.Storeのインスタンスにアクセスする方法を説明します。Ember DataはControllerRoutestoreというプロパティを定義し、ここにDS.Storeのインスタンスを設定します。これにより、ControllerRouteの中ではthis.storeでストアにアクセスできます。

そしてストアにデータを読み込むにはストアのpush()メソッドを利用します。push()メソッドの第一引数はモデル名、第二引数はデータの本体です。

データが関連を持っている場合、関連名をキーとして関連先データのIDを指定します。

さて、これで準備完了です。画面に表示して動作を確認してみましょう。

ルーティングを作成します。

App.Router.map(function() {
  this.resource('posts', {path: '/'});
  this.resource('post', {path: '/post/:id'});
});

App.PostsRoute = Ember.Route.extend({
  model: function() {
    return this.store.all('post');
  }
});

App.PostRoute = Ember.Route.extend({
  model: function(params) {
    return this.store.find('post', params.id);
  }
});

ここではストア経由でモデルを取得しています。モデルを取得するにはいくつかの方法があります。

DS.Store#all()

ストアに読み込み済みのモデル全件を取得します。第一引数にはモデル名を指定します。

DS.Store#find()

モデル名とIDを指定してモデルを取得します。もし該当するモデルがストアに存在しなければ、ストアはサーバに対してHTTPリクエストを発行してデータを取得します[4]⁠。ここまでのサンプルではサーバを用意していないのでリクエストは失敗します。

次はテンプレートを作成します。

<script type="text/x-handlebars" data-template-name="posts">
  <h1>ブログ記事一覧</h1>

  <ul>
    {{#each post in model}}
      <li>{{link-to post.title "post" post}}</li>
    {{/each}}
  </ul>
</script>

<script type="text/x-handlebars" data-template-name="post">
  <h1>{{model.title}}</h1>

  <pre>
    {{model.body}}
  </pre>

  <ul>
  {{#each comment in model.comments}}
    <li>{{comment.text}}</li>
  {{/each}}
  </ul>

  {{link-to "戻る" "posts"}}
</script>

この状態でブラウザを表示すると、コメントがブログ記事に関連付けられているのが確認できます。

Ember Starter Kit

REST APIを扱う

ここまででストアに読み込んだデータを扱うことができるようになりました。ここからはREST API経由でデータの取得とデータの保存を解説します。

今までデータを準備していたApp.ApplicationRouteは不要になるので、クラスごと削除してください。

そして、PostsRoutemodel()メソッドではall()メソッドの代わりにfind()メソッドを利用します。

App.PostsRoute = Ember.Route.extend({
  model: function() {
    return this.store.find('post');
  }
});

これで、必要に応じてデータを取得するように設定されました。

しかし、まだデータを保存するサーバを準備していません。サーバの実装も解説したいところですが、それは「実践入門 Ember.js」の枠をはるかに超えてしまうため今回は割愛させてください。動作するサンプルのAPIサーバを用意したので、今回の記事ではこのサーバを使うよう設定します[5]⁠。

APIサーバのURLは次のとおりです。

それでは、引き続きこのAPIサーバを使うための設定を解説します。

DS.Adapter

Ember Dataでデータの取得元を指定するためにはDS.Adapterを利用します。Ember DataにはDS.Adapterのサブクラスがいくつか用意されていて、デフォルトではREST APIをデータの取得元として扱うDS.RESTAdapterが利用されます[6]⁠。

DS.RESTAdapterは、以下の規則に沿ってHTTPリクエストを発行します。

メソッド URL
store.find('post'); /posts
store.find('post', 1); /posts/1
store.find('post', {page: 2}); /posts?page=2

この規則はカスタマイズ可能ですが、なるべくこの規則に沿ってAPIを実装するほうが手間が少なくなります。

では先ほど紹介したAPIサーバを利用するための設定を行います。

App.ApplicationAdapter = DS.RESTAdapter.extend({
  host: 'https://tricknotes-gihyo-ember-07.herokuapp.com',
  namespace: 'v1'
});

すべてのモデルに共通するアダプタはApplicationAdapterという名前で定義します。もしPostComment専用のアダプタを作成したい場合は、PostAdapterCommentAdapterといった「モデルのクラス名+Adapter」というクラス名のアダプタを定義してください。

ではここで登場した設定項目を説明します。

host

APIサーバのスキームとホスト名を指定します。指定しない場合は現在のURLwindow.location.originが利用されます。

namespace

APIの名前空間を指定します。例えばnamespace: 'v1'が設定されていると、/posts/1というURLの代わりに/v1/posts/1に対してリクエストが発行されます。今回利用するAPIサーバではいろいろな形式のJSONを扱う例を紹介したいので、各セクション毎に別のnamespaceを用意しました。

これで、サンプルサーバを利用する設定が完了しました。

次はAPIサーバが返すべきJSONの形について考えてみましょう。

DS.Serializer

JSONに含まれるデータとモデルのマッピングにはDS.Serializerを使います。デフォルトでは、DS.RESTSerializerというREST APIに特化したシリアライザが利用されます。

このDS.RESTSerializerをカスタマイズするとクライアントサイドで自由なマッピングを指定できますが、まずはカスタマイズをせずにこのシリアライザが期待する形のJSONを準備することにします。

ブログ記事一覧で返すべきJSONは次のような形になります。

/v1/posts.json
{
  "posts": [
    {
      "id": 1,
      "title": "はじめての Ember.js",
      "body": "これから Ember.js を始めようという方向けの記事です。"
    },
    {
      "id": 2,
      "title": "公式サイトの歩き方",
      "body": "http://emberjs.com/ の解説です。"
    }
  ],
  "comments": [
    {
      "id": 1,
      "text": "はじめまして",
      "post": 1
    },
    {
      "id": 2,
      "text": "入門しました",
      "post": 1
    },
    {
      "id": 3,
      "text": "詳しい説明を知りたいときはまず参考にします。",
      "post": 2
    }
  ]
}

ポイントは次の2点です。

  • JSONのルートのキーはモデル名を使う(オブジェクトが複数あればモデル名の複数形を指定する)
  • 関連するデータがあればレスポンスに含める(今回の例では/postsへのリクエストに対してcommentsをレスポンスに含めている)

これを満たすことで、DS.RESTSerializerがレスポンスのJSONをモデルにマッピングしてくれます。

また、記事詳細で返すべきJSONの形は以下のとおりです。

/v1/posts/1.json
{
   "post": {
      "id": 1,
      "body": "これから Ember.js を始めようという方向けの記事です。",
      "title": "はじめての Ember.js"
   },
   "comments": [
      {
         "id": 1,
         "text": "はじめまして",
         "post": 1
      },
      {
         "id": 2,
         "text": "入門しました",
         "post": 1
      }
   ]
}

記事一覧のJSONとの違いは、全件の記事ではなく一件の記事を対象としたものになったことです。JSONのルートのキーも"posts"から"post"になっています。

postとcommentsのような関連するリソースを扱う場合、サーバでこの形式のJSONを出力するのが困難な場合があります。例えば、次のような場合です。

  • JSON生成に利用するライブラリの都合上、"post"と"comments"を並列に並べるのが困難である
  • commentsの数が膨大で全部をpostのレスポンスに含めるとパフォーマンスが劣化する

こういった場合に対応するため、ここからはこの形式以外のJSONを扱う方法を紹介します。

子リソースを親リソースに埋め込む

ここでは、次のようにpostsの中にcommentsが埋め込まれている場合のJSONの扱い方を解説します。

/v2/posts.json
{
  "posts": [
    {
      "id": 1,
      "body": "これから Ember.js を始めようという方向けの記事です。",
      "title": "はじめての Ember.js",
      "comments": [
        {
          "id": 1,
          "text": "はじめまして"
        },
        {
          "id": 2,
          "text": "入門しました"
        }
      ]
    },
    {
      "id": 2,
      "body": "http://emberjs.com/ の解説です。",
      "title": "公式サイトの歩き方",
      "comments": [
        {
          "id": 3,
          "text": "詳しい説明を知りたいときはまず参考にします。",
        }
      ]
    }
  ]
}

まずはアダプタの設定を変更しましょう。

App.ApplicationAdapter = DS.RESTAdapter.extend({
  host: 'https://tricknotes-gihyo-ember-07.herokuapp.com',
  namespace: 'v2'
});

この形のJSONから子リソースを取得したい場合、DS.EmbeddedRecordsMixinを利用します。

App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
  attrs: {
    comments: {embedded: 'always'}
  }
});
attrs

attrsDS.JSONSerializerDS.RESTSerializerの親クラス)で提供されているプロパティです。ここではデータとモデルのプロパティの対応を設定できます。

embedded

DS.EmbeddedRecordsMixinを使うと、attrsでデータの取得時と送信時での子リソースの扱い方を指定きます(データ送信時の振る舞いについては後述)。ここで指定している{embedded: 'always'}というのは、⁠データ送信時・取得時ともに子リソースを埋め込む」ということを意味します。

非同期で子リソースを取得する(ID参照)

さて、次は子リソースを必要になったタイミングで取得する方法を解説します。JSONには子リソースのIDが含まれますが、実体は含まれていません。

/v3/posts.json
{
  "posts": [
    {
      "id": 1,
      "title": "はじめての Ember.js",
      "body": "これから Ember.js を始めようという方向けの記事です。",
      "comments": [
        1,
        2
      ]
    },
    {
      "id": 2,
      "title": "公式サイトの歩き方",
      "body": "http://emberjs.com/ の解説です。",
      "comments": [
        3
      ]
    }
  ]
}

まずはアダプタの設定を変更しましょう。

App.ApplicationAdapter = DS.RESTAdapter.extend({
  host: 'https://tricknotes-gihyo-ember-07.herokuapp.com',
  namespace: 'v3'
});

「子リソースを親リソースの埋め込む」で作成したPostSerializerは不要なので削除します。

そして、関連に非同期であることを示すフラグを設定します。

App.Post = DS.Model.extend({
  // ...

  comments: DS.hasMany('comment', {async: true})
});

では、この状態で実際に動かしてみましょう。

Ember Starter Kit

記事詳細を表示すると、少し遅れてコメントが表示されるのが確認できます。

実際にどのタイミングでコメントが取得されているのかというと、postテンプレート中でコメントが参照されたタイミングです。

{{#each comment in model.comments}}

ではここで、開発者ツールを利用してこのときのHTTPリクエストを確認してみましょう。

v3.1-comments
画像

コメントの数だけHTTPリクエストが発行されています。もしコメントが大量に存在する場合コメントの数だけHTTPリクエストが発行されるため、表示までに時間がかる場合があります。これを避けるためには、以下のオプションを設定して一度に必要なコメントすべてを取得するようにします。

App.ApplicationAdapter = DS.RESTAdapter.extend({
  // ...

  coalesceFindRequests: true
});
v3.2-comments
画像
Ember Starter Kit

コメントを取得するURLに、idsというパラメータ付きでリクエストが発生するようになりました。このAPIサーバがこの形式に対応していればこちらの方がリクエスト数を減らせます。

非同期で子リソースを取得する(URL参照)

先ほどと同じく、子リソースが必要になったタイミングで取得するという方法ですが、先ほどのID指定の方法とは違って子リソースを表すURLを指定する方法を解説します。

linksというプロパティを使うと、子リソースを取得するURLを指定できます。JSONは以下の形になります。

/v4/posts.json
{
  "posts": [
    {
      "body": "これから Ember.js を始めようという方向けの記事です。",
      "title": "はじめての Ember.js",
      "id": 1,
      "links": {
        "comments": "https://tricknotes-gihyo-ember-07.herokuapp.com/v4/posts/1/comments"
      }
    },
    {
      "body": "http://emberjs.com/ の解説です。",
      "title": "公式サイトの歩き方",
      "id": 2,
      "links": {
        "comments": "https://tricknotes-gihyo-ember-07.herokuapp.com/v4/posts/2/comments"
      }
    }
  ]
}

ではこのJSONを扱うためにアダプタを設定しましょう。

App.ApplicationAdapter = DS.RESTAdapter.extend({
  host: 'https://tricknotes-gihyo-ember-07.herokuapp.com',
  namespace: 'v4'
});

この状態で、どのようなリクエストが発行されているか開発者ツールで確認してみましょう。

v4-comments
画像
Ember Starter Kit

linksプロパティで指定したURLに対してリクエストが発行されています。

子リソースを扱ういくつかの方法を紹介しましたが、どの方法が良い/悪いというのはありません。アプリケーション毎に適切だと考えられる方法を選択してください。

CRUD を扱う

ここまではデータを取得方法を紹介してきましたが、このセクションではデータの作成と削除を紹介します。

まずはアダプタを設定します[7]⁠。

App.ApplicationAdapter = DS.RESTAdapter.extend({
  host: 'https://tricknotes-gihyo-ember-07.herokuapp.com',
  namespace: 'v5'
});

JSONの形式はv1と同じものを使っているため、関連の非同期フラグは外します。

App.Post = DS.Model.extend({
  // ...

  comments: DS.hasMany('comment')
});

次は記事詳細画面からコメントの投稿/削除のUIを準備します。

<script type="text/x-handlebars" data-template-name="post">
  <h1>{{model.title}}</h1>

  <pre>
    {{model.body}}
  </pre>

  <ul>
  {{#each comment in model.comments}}
    <li>{{comment.text}} <a href="#" {{action "deleteComment" comment}}>&times;</a></li>
  {{/each}}
  <li>{{input value=text action="createComment" required=true placeholder="どうでしたか?"}}</li>
  </ul>

  {{link-to "戻る" "posts"}}
</script>

記事詳細画面に対応するコントローラを作成して、コメントの投稿/削除に対応します。

App.PostController = Ember.Controller.extend({
  text: null,
  actions: {
    createComment: function() {
      var controller = this;
      var text = this.get('text');

      var comment = this.get('model.comments').createRecord({text: text});

      comment.save().then(function() {
        controller.set('text', null);
      }, function() {
        alert('保存に失敗しました');

        comment.unloadRecord();
      });
    },

    deleteComment: function(comment) {
      comment.destroyRecord();
    }
  }
});

新しく登場した記述を解説します。

createRecord()

モデルのオブジェクトを生成するメソッドです。ここではpostの関連であるcommentsに対してcreateRecord()メソッドを呼び出しているため、記事への関連を保持した状態のコメントを生成します。この状態ではまだサーバに保存はされません。関連を元にせずオブジェクトを生成したい場合はstore.createRecord()を利用します。この場合、第一引数はモデル名、第二引数は初期値を指定します。

save()

モデルをサーバに保存します。クライアントサイドで生成されたモデルであれば新規保存され、サーバから取得してきたモデルであれば更新されます。サーバに送信されるデータはシリアライザによって決定されます。関連するリソースも一緒にサーバに送信したいという場合は前述のDS.EmbeddedRecordsMixinを使います。サーバに送信されるデータをあらかじめ確認したい場合は、モデルのserialize()メソッドを利用してデータを取得します。また、save()メソッドはPromiseを返します。保存に成否を待ってから実行したい処理がある場合、Promiseのコールバックを利用してください。

unloadRecord()

クライアントサイドのモデルを破棄します。クライアントでモデルが不要になった際に呼び出します。

destroyRecord()

モデルをサーバから削除します。似たような機能を持つdeleteRecord()メソッドもあります。前者はすぐにサーバのデータも削除されるのに対し、後者はsave()メソッドを呼ぶまでサーバのデータは削除されないという違いがあります。

これらのメソッドは、HTTPリクエストを発行してサーバのリソースを更新します。意図した通り動作させるためには、対応するAPIをサーバでサポートしている必要があります。

メソッドとAPIの対応は次のとおりです。

メソッド URL リクエストメソッド
comment.save() (新規) /comments/ POST
comment.save() (更新) /comments/1 PUT
comment.destroyRecord() /comments/1 DELETE

動作するサンプルはこちらです。

Ember Starter Kit

ここまでは、Ember DataのDS.RESTAdapter/DS.RESTSerializerが期待する形のAPIサーバを前提として解説をしてきました。APIサーバを実装しつつアプリケーションを開発する際にはここまでで紹介した方法で十分でしょう。

外部のAPIを扱う

せっかくなので、既存のAPIサーバに対してEmber Dataを使ってクライアントアプリを作る例も紹介します。

サンプルとしてGitHubのユーザ名を検索すると、そのユーザが最近starをつけたリポジトリを見られる」アプリを作ってみましょう。完成イメージは次のとおりです。

  1. GitHubでのログイン名を入力してエンターキーを押します。

    画像
  2. ユーザの最近のお気に入り一覧が表示されます。

    画像
Ember Starter Kit

今回対象とするAPIはGitHub APIです。

まずはこのAPIを使うようアダプタを設定します。

App.ApplicationAdapter = DS.RESTAdapter.extend({
  host: 'https://api.github.com'
});

今回はユーザとリポジトリさえあれば十分なので、以下のドキュメントを参考にモデルを定義します。

App.User = DS.Model.extend({
  login: DS.attr('string'),
  avatar_url: DS.attr('string'),

  starred: DS.hasMany('repo', {async: true})
});

App.Repo = DS.Model.extend({
  name: DS.attr('string'),
  full_name: DS.attr('string'),
  html_url: DS.attr('string'),
  description: DS.attr('string'),
  language: DS.attr('string'),
  watchers: DS.attr('number'),
  owner: DS.attr() // owner はオブジェクトが渡ってくるので型変換は行わない
});

次は、GitHub APIのレスポンスを上手くモデルにマッピングするために、シリアライザを定義します。

App.UserSerializer = DS.RESTSerializer.extend({
  primaryKey: 'login',

  normalizePayload: function(payload) {
    payload.links = {
      starred: payload.url + '/starred'
    };

    return {
      user: payload
    };
  }
});

App.RepoSerializer = DS.RESTSerializer.extend({
  normalizePayload: function(payload) {
    return {
      repo: payload
    };
  }
});

細かく見ていきましょう。

primaryKey

プライマリーキーとして扱うプロパティを指定します。デフォルトはidです。GitHub APIではユーザのJSONにidが含まれているのですが、今回のアプリケーションではログイン名をキーにしてユーザを取得するため、モデルを簡単に扱うためにloginプロパティをIDとみなすことにします。

normalizePayload

APIから取得したJSONをEmber Dataで扱う形に変換するためのメソッドです。引数にはサーバから取得したJSONがそのまま渡ってくるので、先ほど紹介した形に加工して戻り値に指定します。デフォルトの実装では引数で渡されたJSONをそのまま返すようになっています。

ここまででGitHub APIを扱う準備が完成しました。あとはルーティングとテンプレートを作成して実際に動かしてみましょう。

ルーティングは以下のとおりです。

App.Router.map(function() {
  this.resource('user', {path: 'user/:id'});
});

App.IndexRoute = Ember.Route.extend({
  model: function() {
    return this.store.all('user');
  }
});

App.UserRoute = Ember.Route.extend({
  model: function(params) {
    return this.store.find('user', params.id);
  }
});

App.IndexController = Ember.Controller.extend({
  name: null,

  actions: {
    addUser: function() {
      var user = this.store.find('user', this.get('name'));

      this.set('name', null);

      this.transitionToRoute('user', user);
    }
  }
});

テンプレートは次のとおりです。

<script type="text/x-handlebars">
  <h1>GitHub star viewer</h1>

  {{outlet}}
</script>

<script type="text/x-handlebars" data-template-name="index">
  @{{input value=name action="addUser" placeholder="username(GitHub)"}}

  {{#if model.length}}
    <h2>最近検索したユーザ</h2>
  {{/if}}
  <ul>
  {{#each user in model}}
    <li>
      <img {{bind-attr src=user.avatar_url}} width="20px" height="20px"/>
      {{link-to user.id "user" user}}
    </li>
  {{/each}}
  </ul>
</script>

<script type="text/x-handlebars" data-template-name="user">
  <img {{bind-attr src=model.avatar_url}} width="20px" height="20px"/>
{{model.id}}

<ul>
  最近 star したリポジトリ
  {{#each repo in model.starred}}
    <li>
      <img {{bind-attr src=repo.owner.avatar_url}} width="20px" height="20px"/>
      <a {{bind-attr href=repo.html_url}} target="_blank">{{repo.full_name}}</a>
      [{{repo.watchers}}]
      #{{repo.language}}
      <div>
        {{repo.description}}
      </div>
    </li>
  {{/each}}
</ul>

{{link-to "戻る" "index"}}
</script>

このように、モデルを定義した上でシリアライザを適切に設定すると、既存のAPIに対するクライアントを簡単に作成できます。

まとめ

今回はEmber Dataについて解説しました。Ember Dataには今回解説したもの以外にもいつくかの部品が存在します。さらに詳しい説明は公式ドキュメントを参照してください。

次回は、開発およびデプロイには欠かせないビルドツールであるEmber CLIember-railsを解説する予定です。

おすすめ記事

記事・ニュース一覧