FixtureAdapterによるインメモリデータ – Ember.js入門(16)

2014.01.05

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

渡辺です。

今回は、開発やテストの時に便利なFixtureAdapterを解説します。

FixtureAdapterとは?

FixtureAdapterは、Modelをインメモリで管理するember-dataのアダプタです。JavaScriptのコードで初期データを定義しておけば、アプリケーションの実行時にstoreからModelを取得することができます。RESTAdapterを利用する場合はサーバプログラムを先に実装しなければならないため、開発やテスト時にクライアントサイドの動作確認をするために利用できます。

FixtureAdapterの設定

ember-dataはデフォルトでRESTAdapterを利用します。FixtureAdapterを利用する場合は、次のようにしてアプリケーションのApplicationAdapterに設定します。

window.App = Ember.Application.create();
App.ApplicationAdapter = DS.FixtureAdapter.extend();

Fixtureの追加

Fixtureとしてメモリにロードするデータは、各ModelのFIXTURESに配列として定義します。

App.Category = DS.Model.extend({
    name: DS.attr('string')
});
App.Category.FIXTURES = [
    {
        id: 1,
        name: 'お知らせ'
    },
    {
        id: 2,
        name: 'Ember.js入門'
    }
];

この時、必ず一意となるidを含めなければなりません。また、Modelは暗黙的にid属性を持つので再定義はしないでください(ここではApp.Category)。ember-dataは整数または文字列のidによりリソースの一意性を判断します。Fixtureとして登録する場合は適当なidをつけておきましょう。

なお、FixtureはREST APIが実装されれば使わなくなる機能です。FIXTURESの定義を行うコードは独立したソースファイルとして作成しておくと良いでしょう。私の場合は、modelの定義全体をmodel.jsに、FIXTURESの定義をmodel.fixtures.jsに書くようにしています。

Modelの取得

Modelをメモリからロードするには、storeのfindメソッドを利用します。

idを指定して1件を取得する

特定のModelを取得したい場合、findメソッドの第1引数にModelのlookup名を指定し、第2引数にidを指定します。

App.CategoryRoute = Ember.Route.extend({
  model: function() {
    return this.store.find('category', 1);
  }
});

全件を取得する

登録されているModelを全件取得したい場合は、findメソッドの第1引数にModelのlookup名を指定します。

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

create/saveの扱い

FixtureAdapterではアプリケーションで新しいレコードを作成しても、サーバに保存されるわけではありません。メモリ内で一時的に保存されますが、再読込をすれば消えてしまいます。次のようにFixtureAdapterで新しいレコードを作成した場合、idは自動的にセットされ、メモリにロードされます。

this.store.createRecord('entry');

実際にメモリにロードされたかどうかは、Chrome拡張のEmber Inspectorで確認することができます。非常に便利なツールなので、Ember.jsのアプリケーションを開発するのであれば、必ずインストールしておきましょう。

fixtue_in_debugger-3

Fixtureのリレーション

Modelにリレーションが定義されている場合は、対応する属性にリレーションするModelのidを定義します。例えば、前回作成したSiteとEnvの2つのModelがあるとします。

App.Site = DS.Model.extend({
    name: DS.attr('string'),
    env: DS.belongsTo('env')
});
App.Env = DS.Model.extend({
    name: DS.attr('string'),
    debug: DS.attr('boolean'),
    host: DS.attr('string'),
    site: DS.belongsTo('site')
});

Siteのenv、Envのsiteがリレーション対象の属性であるため、それぞれに対象ModelのIDを指定します。

App.Site.FIXTURES = [
    {
        id: 1,
        name: 'Developers IO',
        env: 1
    }
];
App.Env.FIXTURES = [
    {
        id: 1,
        name: 'production',
        debug: false,
        host: 'dev.classmethod.jp',
        site: 1
    }
];

なお、次のようにして、片方のみにリレーションを定義することもできます。

App.Site.FIXTURES = [
    {
        id: 1,
        name: 'Developers IO',
        env: 1
    }
];
App.Env.FIXTURES = [
    {
        id: 1,
        name: 'production',
        debug: false,
        host: 'dev.classmethod.jp'
    }
];

この場合、store.find('site', 1)で取得したModelからenvを参照する(遅延ロードされる)ことはできますが、store.find('env', 1)で取得したModelからsiteを参照することはできません。最終的にはREST APIを作成することになるため、先を見越して設計しておく必要があります。

また、ONE-TO-MANY, MANY-TO-MANYなどの場合は、IDではなくIDの配列を指定します。

App.Category = DS.Model.extend({
    name: DS.attr('string'),
    entries: DS.hasMany('entry')
});
App.Entry = DS.Model.extend({
    title: DS.attr('string'),
    postedAt: DS.attr('date'),
    content: DS.attr('string'),
    category: DS.belongsTo('category')
});
App.Category.FIXTURES = [
    {
        id: 1,
        name: 'お知らせ',
        entries: [1, 2]
    }
];
App.Entry.FIXTURES = [
    {
        id: 1,
        title: 'お知らせ1',
        content: 'お知らせ1',
        category: 1
    },
    {
        id: 2,
        title: 'お知らせ2',
        content: 'お知らせ2',
        category: 1
    }
];

まとめ

今回は開発時などに便利に利用できるFixtureAdapterを解説しました。フロントエンドとバックエンド(サーバ)で開発者が分担している時や、学習目的でEmber.jsを試してみたい時には非常に便利な機能です。ただし、最終的にはRESTAdapterを利用してサーバからデータを取得したりデータを更新したりすることになります。便利だからといって複雑すぎるリレーションをFixturesとして構築しても、再設計する羽目になるのでご注意ください。

次回はModelとFixtureAdapterを使ったRouteの基本を解説する予定です。