Skip to content
This repository was archived by the owner on Jan 22, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions addon/models/resource.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const Resource = Ember.Object.extend(ResourceOperationsMixin, {
_attributes: null,

/**
Flag for new instance, e.g. not peristed
Flag for new instance, e.g. not persisted

@property isNew
@type Boolean
Expand Down Expand Up @@ -413,21 +413,24 @@ Resource.reopenClass({
`attributes`, `links` and `relationships`
*/
create(properties) {
properties = properties || {};
const prototype = {};
const attrs = Ember.String.w('_attributes attributes links meta relationships');
for (let i = 0; i < attrs.length; i++) {
prototype[attrs[i]] = {};
}

// JSONAPI ids MUST be strings.
// Without an id we default isNew to true (unless otherwise specified)
if (properties.hasOwnProperty('id')) {
properties.id = properties.id.toString();
} else if (typeof properties.isNew === 'undefined') {
properties.isNew = true;
}

const instance = this._super(prototype);
if (properties) {
if (properties.hasOwnProperty('id')) {
// JSONAPI ids MUST be strings.
properties.id = properties.id.toString();
}
instance.setProperties(properties);

instance.setProperties(properties);
}
let type = singularize(instance.get('type'));
let msg = (type) ? Ember.String.capitalize(type) : 'Resource';
let factory = 'model:' + type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ let <%= classifiedModuleName %> = Resource.extend({

getDefaults() {
return {
isNew: true,
attributes: {}
};
}
Expand Down
4 changes: 3 additions & 1 deletion tests/unit/adapters/application-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ test('#findRelated is called with optional type for the resource', function (ass
});

test('#createResource', function(assert) {
assert.expect(6);
assert.expect(8);
let done = assert.async();

const adapter = this.subject({type: 'posts', url: '/posts'});
Expand All @@ -287,6 +287,7 @@ test('#createResource', function(assert) {
let newResource = postFactory.create(data);

assert.equal(newResource.get('id'), null, 'new resource does not have an id');
assert.equal(newResource.get('isNew'), true, 'new resource isNew');

adapter.serializer = { serialize: function () { return data; } };
let persistedResource = postFactory.create(postMock.data);
Expand All @@ -301,6 +302,7 @@ test('#createResource', function(assert) {
'#fetch called with url and options with data'
);
assert.equal(newResource.get('id'), postMock.data.id, 'new resource now has an id');
assert.equal(newResource.get('isNew'), false, 'new resource no longer isNew');
assert.deepEqual(resp, newResource, 'response is the same resource instance sent as arg');
done();
});
Expand Down
26 changes: 21 additions & 5 deletions tests/unit/models/resource-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,25 @@ moduleFor('model:resource', 'Unit | Model | resource', {
}
});

test('it creates an instance, default flag for isNew is false', function(assert) {
test('it creates an instance', function (assert) {
let resource = this.subject();
assert.ok(!!resource);
assert.equal(resource.get('isNew'), false, 'default value for isNew flag set to `false`');
});
test('creating an instance WITHOUT id has flag for isNew set to true', function(assert) {
let resource = this.subject();
assert.equal(resource.get('isNew'), true, 'without id, default value for isNew flag set to `true`');
});
test('creating an instance WITH id has flag for isNew set to false', function(assert) {
let resource = this.subject({id: 1});
assert.equal(resource.get('isNew'), false, 'without id, default value for isNew flag set to `false`');
});
test('creating an instance allows isNew regardless of id/defaults', function (assert) {
let notIsNewResource = this.subject({isNew: false});
let yesIsNewResource = this.subject({id: 1, isNew: true});

assert.equal(notIsNewResource.get('isNew'), false, 'without id, isNew property is honored');
assert.equal(yesIsNewResource.get('isNew'), true, 'with id, isNew property is honored');
});
test('in creating instances, ids are cast to string', function (assert) {
let id = 1;
let post = this.container.lookup('model:post').create({
Expand Down Expand Up @@ -118,7 +131,8 @@ test('attr() helper creates a computed property using a unique (protected) attri

test('#changedAttributes', function(assert) {
let post = this.container.lookup('model:post').create({
attributes: {id: '1', title: 'Wyatt Earp', excerpt: 'Was a gambler.'}
id: 1,
attributes: {title: 'Wyatt Earp', excerpt: 'Was a gambler.'}
});
assert.equal(post.get('excerpt'), 'Was a gambler.', 'excerpt is set "Was a gambler."');
post.set('excerpt', 'Became a deputy.');
Expand All @@ -131,7 +145,8 @@ test('#changedAttributes', function(assert) {

test('#previousAttributes', function(assert) {
let post = this.container.lookup('model:post').create({
id: '1', attributes: {title: 'Wyatt Earp', excerpt: 'Was a gambler.'}
id: '1',
attributes: {title: 'Wyatt Earp', excerpt: 'Was a gambler.'}
});
assert.equal(post.get('excerpt'), 'Was a gambler.', 'excerpt is set to "Was a gambler."');
post.set('excerpt', 'Became a deputy.');
Expand All @@ -144,7 +159,8 @@ test('#previousAttributes', function(assert) {

test('#rollback resets attributes based on #previousAttributes', function(assert) {
let post = this.container.lookup('model:post').create({
id: '1', attributes: {title: 'Wyatt Earp', excerpt: 'Was a gambler.'}
id: '1',
attributes: {title: 'Wyatt Earp', excerpt: 'Was a gambler.'}
});
assert.equal(post.get('excerpt'), 'Was a gambler.', 'excerpt is set to "Was a gambler."');
post.set('excerpt', 'Became a deputy.');
Expand Down