Not possible to use shorthand route handlers if RestSerializer is used? (ember-cli-mirage) - ember.js

I set up a simple Ember Twiddle to show you my error that is occurring when trying to update a model.
It's considerable that I'm using ember-cli-mirage for mocking the data.
According to the docs, I created a shorthand route that should handle the PUT request.
It does, but with the error: Your handler for the url /api/shops/1 threw an error: Cannot convert undefined or null to object
When using the JSONAPISerializer, everything is working with shorthands (mirage/config.js) and I'm able to update models, but in my case I have to use the RESTSerializer with serialized IDs in the responses.
The request payload when I'm sending the model's attrs are without Id at the end of the property name, f.e.:
// attrs object in PUT request
{
name: "Shop 1",
city: "1" // belongsTo relationship,
}
Now Mirage is trying to find those properties on the respective database model that has to be updated, but cannot find it, because in the database it's cityId and not just city...
I also found this issue report and it’s working, but I was hoping I could avoid something like this. As far as I can remember, in previous versions of ember-cli-mirage (v0.1.x) it was also not needed to override the normalize method in the serializer to be able to make use of the RestSerializer with serializedIds…
My question is:
Is there a way to stick to shorthand route handlers only, or do I really have to write a helper or other custom solution only because I have to use the RestSerializer?
That would be really sad, but at least I would know then.
Thanks for your support!

Short answer: it looks like you need the custom serializer for now until the bug fix for it is merged.
Long answer: that issue looks to be an issue that occurred in the 0.2 -> 0.3 upgrade for Mirage, likely because of underlying DB changes made in Mirage. It'll probably get fixed, but for now you'll need to work around it.

Related

Ember Data TypeForRoot no longer being called

We are currently on Ember Data 1.0.0-beta.18, Ember 1.12 and CLI 0.2.7.
Since this last update, we are getting ember data assertion warnings like the following:
[Warning] WARNING: Encountered "open_requests" in payload, but no model was found for model name "open-request" (resolved model name using vault#serializer:appuser:.typeForRoot("open_requests")) (vendor.js, line 15423)
I also noticed that a console log we included in the appuser serializer is no longer called:
export default DS.RESTSerializer.extend( {
typeForRoot: function(root) {
console.log('appuser serializer called', root);
if (root === 'open_requests') return this._super('openrequest');
return this._super(root);
},
});
I can confirm that TypeForRoot was called prior to this update. We have had a number of other issues since upgrading and it seems that they could all be related in some way to the serializers, so the questions are why are we getting these warnings and why is typeForRoot no longer being called?
Ember Data switched to modelNameFromPayloadKey, typeForRoot is no longer used in the code unless you are specifically calling it.
http://emberjs.com/api/data/classes/DS.RESTSerializer.html#method_typeForRoot
beta.18 introduced a potentially breaking change - looks like it caused your app to break..
Short answer: rename typeForRoot to modelNameFromPayloadKey
From the CHANGELOG
[#3034] POTENTIALLY BREAKING CHANGE if you override typeForRoot currently introduce modelNameFromPayloadKey and deprecate typeForRoot #fivetanley
RESTSerializer#typeForRoot has been deprecated. You can use RESTSerializeer#modelNameFromPayloadKey instead.
Added RESTSerializer#payloadKeyFromModelName. This allows you to
typeKey on Snapshots and Model classes has been deprecated. Use modelName instead. specify the outgoing root key for a JSON payload.
From the Blog Post
DS.RESTSERIALIZER.TYPEFORROOT IS NOW DS.RESTSERIALIZER.MODELNAMEFROMPAYLOADKEY
To gain more consistency in the naming change of typeKey to modelName, typeForRoot has been renamed to modelNameFromPayloadKey. The function serves the same purpose, so this should be a quick refactor you can achieve via search and replace in your project. While calling typeForRoot will trigger a deprecation warning, overriding in a subclass won't.

Ember Data override find method

I need to override the find() method in ember-data to make it compatible with my app. Its not a huge modification that I have to do, but I don't know where to start.
So far when I try to do this : this.store.find('enquiry'); Ember-Data is trying to fetch information from http://localhost/enquiries instead of http://localhost/enquiry. My problem is that I don't need to get the plural of my url..
I thought also using the jquery method but, I would rather using Ember-Data for this. How can I do that ?
Another question : After this is working, is Ember-Data generate dynamically the model in the app ? Because I have a lot field in my JSON and I can't write them down manually...
Can I do something like this :
App.Store = DS.Store.extend({
adapter: '-active-model'
});
App.Enquiry = DS.Model.extend();
Thanks for your help !
This page will show you exactly how to use a custom adapter in your application. And this page will show you how to override a method in your subclass.
I didn't see your response on the Ember forum yesterday, but in my opinion, you'd still be better off writing your own adapter. It seems like you're going to do more work trying to modify the REST adapter than if you just created your own.
But if you still want to extend the rest adapter, here is how:
App.ApplicationAdapter = DS.RESTAdapter.extend({
find: () {
//...
}
}):
As for your second question, no, Ember-Data will not pick up the fields automatically. I'm pretty sure it'll throw an error if you include fields in your JSON that are not declared in the corresponding model. This is by design. If you don't know your fields at development-time, how can you use them in templates or controllers?

ember-data adapter to read from cloudant RESTful API

The cloudant RESTful API is fairly simple but doesn't match the way ember-data expects things to be. How can I customize or create an Adapter that deals with these issues...
In my specific case I only want to load records from one of several secondary indexes (ie. MapReduce fnctions).
The URL for this is below, where [name] and [view] would change depending on user selection or the route I am in.
https://[username].cloudant.com/[db_name]/_design/[name]/_view/[view]
Looking at the ember-data source there doesn't seem to be an easy way of defining URLs like this. I took a look at findQuery and it expects to send any variables through as url params not as part of the actual URL itself.
Am I missing something? Is there an obvious way of dealing with this?
Then the data comes back in a completely different format, is there a way to tell ember what this format is?
Thanks!
I had similar problem where URL's are dynamic. I ended up creating my own adapater by extending DS.RESTAdapter and overriding the default buildURL method. For example:
App.MyAdapter = DS.RESTAdapter.extend({
buildURL: function(record, suffix) {
var username, db_name, name, view;
// Do your magic and fill the variables
return 'https://'+username+'.cloudant.com/'+db_name+'/_design/'+name+'/_view/'+view;
}
});
I ended up also defining my own find, findAll, findQuery, createRecord, updateRecord, deleteRecord etc. methods as I had to pass more variables to buildURL method.
If returning data is in different format then you can also write your own serializer by extending DS.JSONSerializer and define your own extraction methods extract, extractMany etc.
You should evaluate how well your API follows the data format required by ember/data RESTAdapter. If it is very different then it's maybe better to use some other component for communication like ember-model, ember-restless, emu etc, as ember-data is not very flexible (see this blog post). You can also write your own ajax queries directly from routes model hooks without using ember-data or other components at all. It is not very hard to do that.

Ember data entity id generation

When new model is created and saved with RESTAdapter its Id property is undefined, because my backend is responsible for id generation. So when I return to grid there is 2 same entities: first - with empty Id (from RESTAdapter cache, I think) and second - with correct Id returned from backend.
Any ideas? Maybe it is posiible to disable RESTAdapter cache?
UPDATE
My code for entity creation.
submit:function () {
var manager = App.store.createRecord(App.Manager, {
firstName:this.get('firstName'),
lastName:this.get('lastName'),
speciality:this.get('speciality')
});
App.store.commit();
this.get('controller').transitionTo('managers');
return false;
}
NEW UPDATE
Thanks to Mike Grassotti hints. Here some details for my issue.
One antity have Id, another have no Id.
If I remove App.store.commit() code, there is no POST to server and only entity without Id will be displayed.
This entity has isLoaded=false and isError=true.
When new model is created and saved with RESTAdapter its Id property is undefined, because my backend is responsible for id generation.
Right, but there is nothing unusual about this - ember expects id generation to be done by the backend.
So when I return to grid there is 2 same entities: first - with empty Id (from RESTAdapter cache, I think) and second - with correct Id returned from backend.
OK. What do you mean by same 2 entities - surely they are different js objects. Try logging each of them to console like this:
console.log(entityOne.toString());
console.log(entityTwo.toString());
Any ideas?
There are many things that could cause this to happen. Sounds like somehow you are creating two new records and saving just one of them. Or could be the API response does not match what ember expects, causing an extra record to get created.
Try to enable logging on your records, then watch console so you can see what's going on as your model is saved. Hopefully this will give you some insight into when/how the extra record is being created.
record.set("stateManager.enableLogging", true)
Inspect browser communication with your api and compare JSON to see if it matches what the ember rest adapter expects.
Post that JSON and the rest of your source code (model definition, etc.) to Stack Overflow, maybe a second set of eyes will help.
Check this post for some other debugging tips: http://www.akshay.cc/blog/2013-02-22-debugging-ember-js-and-ember-data.html
Maybe it is posiible to disable RESTAdapter cache?
RESTAdapter does not maintain a separate cache of model objects. And since you are not trying to do anything special, there should be no need to take a step like that.
Many thanks to Mike Grassotti, I have found an answer to my question.
The good question was
With App.store.commit() back in, what does the JSON response from
server look like?
+1 for that comment.
I can't find any info in ember-data documentation for that, so some links still would be helpful for me. I change the result returned from backend and everything works fine now.
{
"manager": {
"firstName": "test",
"lastName": "test",
"speciality": "test",
"id": "acd325ac-03eb-419e-be8a-d4ac42e8c235"
}
}

Ember data - How to update record

I did implement some code with ember-data talking to a sinatra json-app. Method findAll works as expected and load of records.
Also I did implement the updateRecord-method in the DS.Store.create, but don't really know how to update and commit. Please, see the code here (for sake of brevity, I didn't include the jquery functions): http://pastie.org/3197008
I tried the following:
a = Todos.records.objectAt(0).set("text", "should be so")
a.store.commit()
But I get the following error: TypeError: Object (subclass of DS.State) has no method 'enter'
How should I update records? Or did I forget to implement something for the update?
Thanks in advance!
I had the same problem. I think this is a bug in ember-data. The problem is that the code was not properly initializing certain substates, and those substates were not state instances but rather state classes.
I fixed the problem by defining a function that generates a new state instance (with properly created substates) each time it is called. You can find my changes here.
I also requested that the ember-data folks pull my fix, so hopefully this issue will disappear soon. You can view the pull request for discussion.
i had the same problem this morning. Use the emberjs git version