Skip to content

Commit

Permalink
Change _normalizeTypeKey to defer normalization to the container
Browse files Browse the repository at this point in the history
First, remember that isolated containers have no normalization. When
testing with isolated containers, the user-entered model key becomes
the container object name as well as the type key.

For example, in a unit test this modelFor works like this:

* `modelFor("SomeItem")`
* Looks for `"model:SomeItem"` in the container
* This is normalized to `"model:SomeItem"` (unit tests have no
  normalization)
* The object is returned. In Ember-CLI, a error. In globals Ember,
  `App.SomeItem`.
* The typeKey is set to the normalized value: `SomeItem`

In an acceptance or app environment the container has a different
resolver. In these cases normalization changes things. For example,
with the Ember-CLI resolver:

* `modelFor("SomeItem")`
* Looks for `"model:SomeItem"` in the container
* This is normalized to `"model:some-item"` (Ember-CLI is dasherizing)
* The object is returned. In Ember-CLI, `app/models/some-item`.
* The typeKey is set to the normalized value: `some-item`

What must be added to this confusing situation is that RESTAdapter
defers to the `typeKey` for model keys. If you change your resolver, you
will change the requests sent to your server and the way data is parsed.
  • Loading branch information
mixonic committed Feb 25, 2015
1 parent f71e90a commit 6e22154
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 32 deletions.
9 changes: 5 additions & 4 deletions packages/ember-data/lib/system/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
InvalidError,
Adapter
} from "ember-data/system/adapter";
import { singularize } from "ember-inflector/system/string";
import {
Map
} from "ember-data/system/map";
Expand Down Expand Up @@ -97,8 +96,6 @@ var Promise = Ember.RSVP.Promise;
var copy = Ember.copy;
var Store;

var camelize = Ember.String.camelize;

// Implementors Note:
//
// The variables in this file are consistently named according to the following
Expand Down Expand Up @@ -1850,7 +1847,11 @@ Store = Ember.Object.extend({
@return {String} if the adapter can generate one, an ID
*/
_normalizeTypeKey: function(key) {
return camelize(singularize(key));
// Delegate to the container for normalization. The container
// requires a ':' to normalize so we add `model:` then slice off
// the first 6 characters to remove the `model:` in the return
// value
return this.container.normalize('model:' + key).slice(6);
}
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var env, store, adapter, Post, Comment, SuperUser;
var env, store, adapter, Post, Comment, SuperUser, EmberCliUser;
var passedUrl, passedVerb, passedHash;
var run = Ember.run;

Expand All @@ -16,12 +16,17 @@ module("integration/adapter/rest_adapter - REST Adapter", {
name: DS.attr("string")
});

EmberCliUser = DS.Model.extend({
name: DS.attr("string")
});

SuperUser = DS.Model.extend();

env = setupStore({
post: Post,
comment: Comment,
superUser: SuperUser,
'ember-cli-user': EmberCliUser,
adapter: DS.RESTAdapter
});

Expand Down Expand Up @@ -169,6 +174,22 @@ test("create - an empty payload is a basic success if an id was specified", func
});
});

test("create dasherized model name is a basic success", function() {
ajaxResponse();
var emberCliUser;

run(function() {
emberCliUser = store.createRecord('ember-cli-user', { name: "The Parley Letter" });
emberCliUser.save().then(async(function(post) {
equal(passedUrl, "/emberCliUsers");
equal(passedVerb, "POST");

equal(post.get('isDirty'), false, "the ember-cli-user isn't dirty anymore");
equal(post.get('name'), "The Parley Letter", "the ember-cli-user was updated");
}));
});
});

test("create - a payload with a new ID and data applies the updates", function() {
ajaxResponse({ posts: [{ id: "1", name: "Dat Parley Letter" }] });
run(function() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,19 +284,6 @@ test("serialize polymorphicType", function() {
});
});

test("serialize polymorphicType with decamelized typeKey", function() {
YellowMinion.typeKey = 'yellow-minion';
var tom, ray;
run(function() {
tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" });
ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" });
});

var json = env.restSerializer.serialize(ray._createSnapshot());

deepEqual(json["evilMinionType"], "yellowMinion");
});

test("normalizePayload is called during extractSingle", function() {
env.registry.register('serializer:application', DS.RESTSerializer.extend({
normalizePayload: function(payload) {
Expand Down
4 changes: 2 additions & 2 deletions packages/ember-data/tests/unit/store/create_record_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ test("creating a record by camel-case string finds the model", function() {
});

equal(record.get('foo'), attributes.foo, "The record is created");
equal(store.modelFor('someThing').typeKey, 'someThing');
equal(store.modelFor('someThing').typeKey, 'some-thing');
});

test("creating a record by dasherize string finds the model", function() {
Expand All @@ -54,7 +54,7 @@ test("creating a record by dasherize string finds the model", function() {
});

equal(record.get('foo'), attributes.foo, "The record is created");
equal(store.modelFor('some-thing').typeKey, 'someThing');
equal(store.modelFor('some-thing').typeKey, 'some-thing');
});

module("unit/store/createRecord - Store with models by camelCase", {
Expand Down
42 changes: 30 additions & 12 deletions packages/ember-data/tests/unit/store/model_for_test.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
var container, store;

var camelize = Ember.String.camelize;
var dasherize = Ember.String.dasherize;
var capitalize = Ember.String.capitalize;

var run = Ember.run;
var env;

function containerNormalize(string) {
return container.normalize('model:'+string).slice(6);
}

module("unit/store/model_for - DS.Store#modelFor", {
setup: function() {
env = setupStore({
blogPost: DS.Model.extend(),
"blog-post": DS.Model.extend()
"blog.post": DS.Model.extend(),
"blog_post": DS.Model.extend(),
"blogPost": DS.Model.extend(),
"BlogPost": DS.Model.extend()
});
store = env.store;
container = store.container;
Expand All @@ -24,25 +30,37 @@ module("unit/store/model_for - DS.Store#modelFor", {
}
});

// In this test, the normalizer is nothing at all. This is the default for
// containers, most notably in unit tests. Note that the Ember application
// container *does* have normalization logic, and that is tested in the next
// test.
test("when fetching factory from string, sets a normalized key as typeKey", function() {
env.replaceContainerNormalize(camelize);

equal(container.normalize('some.post'), 'somePost', 'precond - container camelizes');
equal(store.modelFor("blog.post").typeKey, "blogPost", "typeKey is normalized to camelCase");
equal(containerNormalize('some.post'), 'some.post', 'precond - container does nothing to dots');
equal(store.modelFor("blog.post").typeKey, "blog.post", "typeKey is normalized");
equal(store.modelFor("blog_post").typeKey, "blog_post", "typeKey is normalized");
equal(store.modelFor("blogPost").typeKey, "blogPost", "typeKey is normalized");
});

test("when fetching factory from string and dashing normalizer, sets a normalized key as typeKey", function() {
// Test a container similar to the Ember application container- one with
// normalization.
test("when fetching factory from string and non-default normalizer, sets a normalized key as typeKey", function() {
env.replaceContainerNormalize(function(fullName) {
return dasherize(camelize(fullName));
return 'model:'+capitalize(camelize(fullName.slice(6)));
});

equal(container.normalize('some.post'), 'some-post', 'precond - container dasherizes');
equal(store.modelFor("blog.post").typeKey, "blogPost", "typeKey is normalized to camelCase");
equal(containerNormalize('some.post'), 'SomePost', 'precond - container titlizes');
equal(store.modelFor("blog.post").typeKey, "BlogPost", "typeKey is normalized");
equal(store.modelFor("blog_post").typeKey, "BlogPost", "typeKey is normalized");
equal(store.modelFor("blog-post").typeKey, "BlogPost", "typeKey is normalized");
});

test("when returning passed factory, sets a normalized key as typeKey", function() {
env.replaceContainerNormalize(function(fullName) {
return 'model:'+capitalize(camelize(fullName.slice(6)));
});

var factory = { typeKey: 'some-thing' };
equal(store.modelFor(factory).typeKey, "someThing", "typeKey is normalized to camelCase");
equal(store.modelFor(factory).typeKey, "SomeThing", "typeKey is normalized");
});

test("when returning passed factory without typeKey, allows it", function() {
Expand Down

0 comments on commit 6e22154

Please sign in to comment.