Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change _normalizeTypeKey to defer normalization to the container #2821

Closed
wants to merge 4 commits into from

Conversation

mixonic
Copy link
Member

@mixonic mixonic commented Feb 25, 2015

Let's talk about Ember-Data model resolution works in this PR.

First, remember that isolated containers have no normalization. When testing with isolated containers (unit tests), the user-entered model name becomes the factory name requested from the container as well as the typeKey.

For example, in a unit test 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 factory is returned. In Ember-CLI, an 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 factory is returned. In Ember-CLI, that from app/models/some-item.
  • The typeKey is set to the normalized value: some-item

There are several points of confusion IMO. I'd like to suggest two followup issues:

  • Most developers do not realize that unit testing uses a different resolver/normalization than apps and acceptance tests. Acceptance tests are more "forgiving". If you camelCase in an Ember-CLI unit test you will get model-not-found errors. IMO (and I've PR this before, got it merged, and it was ripped out), Ember-Data should normalize model names before passing them to the container. This doesn't mean the typeKey should not be based on the container normalization (should not matter, should be an internal anyway), but that an additional normalization step would be introduced at the beginning of modelFor. This normalization would ensure that Ember-Data, when there is no normalization provided by the container, always normalizes its own requests to camelCase or some other consistent format instead of blindly trying to trust user input.
  • 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.

See also:


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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this test is incorrect.

  • You should never manually set a typeKey.
  • The YellowMinion was registered into the container with camelCase.
  • This is a unit test, there is no normalization of model names

Looking into polymorphics, I am confused by the type usage. Sometimes it seems like we trust the typeKey (serialization) other times we camelize it (relationType).

@bmac
Copy link
Member

bmac commented Feb 26, 2015

I'm also in favor of adding a rootForType with a default of camelization for backwards compatibility. I now believe the typeForRoot that I used in #2766 was a mistake.

Overall I like this pr. I wanted to bring up a that one of @tomdale's reasons for suggesting Ember Data issues a deprecation warning when it detects caps (that may not have been well communicated in the comment in #2766) was the fear that users would have to change their type argument the store.find call when migrating from globals to the Ember CLI resolver.

@mixonic
Copy link
Member Author

mixonic commented Feb 26, 2015

@bmac I believe a user can move app code between globals and Ember-CLI smoothly today. The default ember application container normalization should be sufficient.

Moving unit tests is the mess: There is no normalization, but the model names in the container have changed. Thus you end up being forced into dasherized format in unit tests.

I'll add rootForType to this PR.

@mixonic mixonic force-pushed the normalize-type-key branch 3 times, most recently from 2a42c50 to 8165ff7 Compare February 26, 2015 04:44
@mixonic
Copy link
Member Author

mixonic commented Feb 26, 2015

Slight change of plans: I did not implement a rootForType, as it is would only be used in serializeIntoHash. Instead I just camelize in serializeIntoHash.

Need to add a test for new serializeIntoHash behavior. It should assert that the current behavior in Ember-CLI (that a payload namespace is camelCased) occurs even when dasherized names are used in the container.

Did some cleanup of embedded records mixin. The tests make a lot of assumptions about camelCasing. Need to add some for serialization.

@mixonic
Copy link
Member Author

mixonic commented Feb 28, 2015

  • More tests
  • Introduce typeForPayload in the JSONSerializer. I added it to the JSONSerializer because embedded records mixin is tested against that serializer, and this method is required for polymorphic serialization. typeForPayload allows us to not leak the typeKey. An Ember-CLI app (with dasherized keys) and a globals app (with camelCase keys) will send the same polymorphic type string to the server via typeForPayload (camelCase by default for backwards compat).
  • Importantly, I believe this PR changes nothing about how polymorphic type are sent to the server. It also changes nothing about how mixin keys are read from response payloads. So it should be backwards compatible.

@bmac @igorT @stefanpenner I'd appreciate a look. I think this is good to go.

@fivetanley
Copy link
Member

@mixonic I think @tomdale and @wycats thought this kind of logic should always delegate to a Resolver. Am I way off track here tomhuda?

@bmac bmac added this to the 1.0.0-beta.16 milestone Feb 28, 2015
mixonic added 4 commits March 7, 2015 17:02
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.
@mixonic mixonic force-pushed the normalize-type-key branch from 468ad0f to e038e41 Compare March 7, 2015 22:02
@mixonic
Copy link
Member Author

mixonic commented Mar 7, 2015

This is rebased and passing. Waiting on a +1 or further discussion.

import DS from "ember-data";
export default DS.RESTSerializer.extend({
typeForRoot: function(root) {
return subRoot.singularize().dasherize();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean Ember CLI users will still need to use a custom Serializer after this pr is merged?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to stay really specific here. I don't think most devs know that a dasherizing typeForRoot can make their ember-cli unit tests work properly (with multi-word model names). The current code will pass a camelized name to the store (and then container, where there is no normalization), and not find the model. That behavior is not changed in this PR.

I would recommend that they use a singularize then dasherize typeForRoot, yeah.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do conventional API's return dasherized responses?

@mixonic
Copy link
Member Author

mixonic commented Mar 13, 2015

We discussed this a bit at the ember-data meeting.

  • Let's introduce a property on classes called modelName, which is always dasherized
  • Let's deprecate getting typeKey
  • We need both typeForRoot and payloadForType, though perhaps the names need more bikeshedding (modelNameFromPayload, modelNameForPayload I suggest)
  • Before the use-dashes-everywhere work can land Ember's default container, the isolated container, and the Ember-CLI container must raise a warning or deprecation notice for camelCase lookups.

@stefanpenner
Copy link
Member

Let's introduce a property on classes called modelName, which is always dasherized

can you also explain what this property will be used for.

Before the use-dashes-everywhere work can land Ember's default container, the isolated container, and the Ember-CLI container must raise a warning or deprecation notice for camelCase lookups.

only the resolver needs these deprecation warnings

@mixonic
Copy link
Member Author

mixonic commented Mar 13, 2015

can you also explain what this property will be used for.

It is the new public interface for model names. Always dasherized, which matches our conventions across the board (once the deprecations are added to the resolvers)

only the resolver needs these deprecation warnings

Ah, so the normalization is different in the three places I listed. It seems correct that the resovler may be the only things that needs to throw, but the normalization should probably be reviewed.

@stefanpenner
Copy link
Member

It is the new public interface for model names. Always dasherized, which matches our conventions across the board (once the deprecations are added to the resolvers)

What are the public usages of this api? (i am just curious why a name placed on a factory is ever needed)

@stefanpenner
Copy link
Member

Ah, so the normalization is different in the three places I listed. It seems correct that the resovler may be the only things that needs to throw, but the normalization should probably be reviewed.

all normalization must go through the resolver

@mixonic
Copy link
Member Author

mixonic commented Mar 13, 2015

What are the public usages of this api? (i am just curious why a name placed on a factory is ever needed)

when building a url in the adapter. during serialization of a polymorphic model. when determining the root property name of a create payload.

all normalization must go through the resolver

This has changed recently. Looks like you're right. I see at least these:

So "the resolver" translates back to my original statement. "Ember's default container, the isolated container, and the Ember-CLI container must raise a warning or deprecation notice for camelCase lookups."

It seems a non sequitur to raise that normalization goes through the resolver. The behavior still needs to change in three situations, correct?

@stefanpenner
Copy link
Member

So "the resolver" translates back to my original statement. "Ember's default container, the isolated container, and the Ember-CLI container must raise a warning or deprecation notice for camelCase lookups."

i want to clarify further, to make sure we remove all mis-behaving code. The resolver is the only thing that knows about naming conventions, and as such it is the only place we should put these deprecations. With one exception, and that is plural/singlular inflections. If other exceptions exist, I strongly suspect that is demonstrating a bug, that we must resolve.

@return {String} the model's name in your request payloads
*/
typeForPayload: function(key) {
return camelize(singularize(key));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is plucking from the payload correct?

@fivetanley
Copy link
Member

only the resolver needs these deprecation warnings

The idea here is that you shouldn't be able to register anything in the container that is not dasherized either.

@stefanpenner
Copy link
Member

The idea here is that you shouldn't be able to register anything in the container that is not dasherized either.

registration itself is some-what of an anti-pattern, most app scenarios should ideally be resolved.

@cah-brian-gantzler
Copy link

Each version of Ember data that comes out I check to see if perhaps this has been completed :) Any idea on when this may make it into a beta? 1.0 is coming quickly and hoping this does not get deferred to 2.x I currently can not use the mock http facility and would very much like to.

@cah-brian-gantzler
Copy link

Looking at the code more closely, this particular problem is indeed fixed.(Tried beta.18, could be fixed earlier though) The correct adapter is being called. My test is still failing because the http-mock is not being installed. I have found that the tests work using http:/localhost:4200/tests but does not work with ember test -s. Any ideas?

@mixonic
Copy link
Member Author

mixonic commented May 29, 2015

I believe much of this has been addressed in beta.18 in other PRs by @fivetanley (thank you sir). I'm closing, though I'd like to port my tests from here forward to master now that his code has landed.

@mixonic mixonic closed this May 29, 2015
@fivetanley
Copy link
Member

@mixonic much of the code left is in #3074

@cah-brian-gantzler
Copy link

Are mocks suppose to be installed when running ember test -s?

@bmac
Copy link
Member

bmac commented Jun 1, 2015

@cah-briangantzler I asked @rwjblue about mocks with ember test -s and he reports that they currently do not work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants