Backbone.Modelから見るBackbone.Collectionとの関連性

このエントリはBackbone.js Advent Calendar 2012の5日目の記事です。

前回のBackbone.Syncとbackbone.localstorage.jsの話の続きで、Backbone.Modelから見るBackbone.Collectionとの関連性についてお話します。

このエントリでお伝えしたいこと。

  1. 何をするとBackbone.ModelとBackbone.Collectionの結びつくか。

はじめに

前回のテストコードですが、Backbone.localstorage.js本家のテストコードを見たところ、どうやらBackbone.Collectionのcreate()を使うのが正しい使い方ようなので、次のように書き直しました。
(ちなみにユニットテストはJasmineを使ってます。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
describe('test localstorage', function() {
beforeEach(function() {
this.collection = new collection();
});

it('test collection create', function() {
this.collection.create({
title: 'hello'
});

var model = this.collection.at(0);
expect(this.collection.localStorage.find(model)).not.toBe(null);
expect(this.collection.localStorage.find(model).title).toBe('hello');
});
});

なんだCollectionのcreate()を使えば良いのか。一件落着!
と思いたいのですが。。。

確か、model.localStorageかmodel.collection.localStorageが存在しない場合、デフォルトのAjaxが動くのは前回確認済みです。上のテストコードのどこを見てもそのようなことはしていませんね。
なにやら黒魔術的な臭いがします。

Backbone.ModelとCollectionの近しい関係

黒魔術的な臭いがする場合は、ソースコードを読むのが一番です。まず、Collectionのcreate()を読みました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Create a new instance of a model in this collection. Add the model to the
// collection immediately, unless `wait: true` is passed, in which case we
// wait for the server to agree.
create: function(model, options) {
var coll = this;
options = options ? _.clone(options) : {};
model = this._prepareModel(model, options);
if (!model) return false;
if (!options.wait) coll.add(model, options);
var success = options.success;
options.success = function(nextModel, resp, xhr) {
if (options.wait) coll.add(nextModel, options);
if (success) {
success(nextModel, resp);
} else {
nextModel.trigger('sync', model, resp, options);
}
};
model.save(null, options);
return model;
},

上はBackbone.jsの766行目辺り。ざっと目を通してすぐ分かりました。

1
model = this._prepareModel(model, options);

怪しすぎるww。
なので、_prepareModel()を読みました。

1
2
3
4
5
6
7
8
9
10
11
12
13
// Prepare a model or hash of attributes to be added to this collection.
_prepareModel: function(model, options) {
options || (options = {});
if (!(model instanceof Model)) {
var attrs = model;
options.collection = this;
model = new this.model(attrs, options);
if (!model._validate(model.attributes, options)) model = false;
} else if (!model.collection) {
model.collection = this;
}
return model;
},

上はBackbone.jsの809行目辺り。ありました。見たかったのはこれです。

1
model.collection = this;

なるほど、こんなところでModelにCollectionがセットされていましたね。
これで、上のテストコードがパスできる理由も分かりました。これですっきりです。

他にもCollectionの中で_prepareModel()呼んでいる場所を調べたところ、create()も含めて4箇所ありました。

まだBackboneの全体を見通せてないので、作ってて所々(?)となることがあります。ソースコード印刷して電車で読むことにしました。

Backbone.js Advent Calendar 2012