myModel.save() => rejected promise with status 201 - ember.js

When I call myModel.save(), in one of my controllers, to insert a new record into the store I get back a promise with isRejected: true.
The reason object has the following attributes:
readyState: 4,
status: 201,
statusText: "created"
The object is created properly in my backend REST service. In fact, if I put the transitionToRoute in the catch(), instead of the then(), everything would appear to be just fine.
What's going on here?

You need to return the object back with your request. This is particularly important because the server should provide an id for that newly created record. Without an id there is no definitive way of updating and being sure you're updating the correct record. The format should follow the same format if you were to find the model.
IE:
{
type: {
id:12312,
property:'value',
otherProperty:'value'
}
}

Related

How to update an existing record when creating a record with ember-data

When I try to create a model instance
record = this.store.createRecord('model', { /* whatever */ });
record.save();
And my API updates an already existing backend record instead of creating a new one. The API returns HTTP 200 [ok] (could also be 202 [accepted]) instead of 201 [created].
What is the ember way to have this record not created in the store if an instance of the same record is already there?
Right now if I "create" a record that turns out to update an existing record X times, I end up having the same record (with the same ID) repeated X times in my ember-data store.
When you use createRecord, you're telling Ember to add a new record to your store.
You need to fetch your record into your store first, if you want to update it:
this.store.find('model', id).then(function(record) {
record.set('property', 'value');
record.save();
});
http://emberjs.com/api/data/classes/DS.Store.html#method_createRecord
Maybe you're looking for this.store.update( ... ), depending on your specific needs: http://emberjs.com/api/data/classes/DS.Store.html#method_update

Ember not saving records when using DS.RESTAdapter

I'm trying to create a new object via the DS.RESTAdapter , but I don't see any activity on the backend (via console or in the db). There's no errors output in the console (using chrome). Reading data via index and show works fine. In my route.rb I have
resource #posts, only: [:index, :show, :new, :create]
After I fill out a form and click submit this line gets called (trying static data to start with)
this.get('store').createRecord('post', {name: 'asdf'});
In the ember inspector in chrome I see under "Data" the new records being created without the ID. I notice the new method in my backend post controller isn't called so is there another step I have to do for the adapter to attempt a REST PUT?
Thanks!
createRecord only creates the record in the store.
To persist that record you need to call save() on it.
// Puts record into store
var newPost = this.get('store').createRecord('post', {name: 'asdf'});
// Persists it
newPost.save();
See: http://emberjs.com/guides/models/persisting-records/

Success callback never triggered with Ember-Data save()

I am trying to use ember-data to get a simple registration form to save on my server. The call technically works, but the success callback is never trigger on the promise, and I have no idea why.
The server receives the data from the front end and successfully saves it to the database. It then returns status code 201 for CREATED. I can see the successful response happening in the Chrome debugger. But even when the server responds with a successful status, the error callback is triggered on the save's promise. I've confirmed this happens every time by putting a debugger; statement in the error callback.
My router's model is hooked up like this:
model: function() {
return this.store.createRecord('registerUser');
}
And I have a simple register function in my controller:
register: function() {
var self = this;
this.get('model').save().then(function() {
self.transitionToRoute('index');
}, function(resp) {
if (resp.responseJSON) {
self.get('model').set('errors', resp.responseJSON.errors);
}
});
}
Every time my server comes back with a response, success or failure, the failure callback is hit. If I have errors in the response (for invalid data or something), the errors are successfully displayed in the form. I can see the request coming in properly, and the data is stored in the database. So, the save is technically successful, but ember doesn't seem to know that it is even though a successful 201 status is returned from the server (which can be verified in the Chrome debugger).
The only thing I can think of is that ember-data's adapter is doing something that I'm not aware of, but I am just using the default RESTAdapter and haven't touched it. Is there anything else
If it makes a difference, the server is running Play 1.2.5. I don't know if that makes a difference in the response's header or something like that.
Any help would be greatly appreciated. Thank you for your time!
Mike
SOLUTION
So, the issue was to do with the JSON response. The two problems:
I did not include an ID in the response
I did not "wrap" the response in a "registerUser". This is necessary to match the model name.
Below is a valid response:
{
"registerUser": {
"id": 11,
"email": "mike999#test.com",
"password": "12345",
"password2": "12345",
"name": "Mike"
}
}
Ember Data is expecting the model in the response, so sending back a success http status doesn't mean it will hit the success endpoint. When it tries to serialize your response (or lack of response) it's probably failing which would be why it's hitting the failure function. A big reason for the response is the id of the record.
The model returned should be in the following format
{
registerUser:{
id: "123",
attr: "asdf"
}
}
https://github.com/emberjs/data/blob/master/TRANSITION.md

publish story using Object API

I am trying to publish stories from my server when people win a game into my web app.
I have folowed the documentation but i apparently do something wrong, here is the url and the datas object i pass into my POST call.
https://graph.facebook.com/'+user_id+'/points.win
var Datas = {
title: '500',
type: 'mygame:points',
image: 'http://mywebsite.jpg',
url: 'https://mywebsite.com',
description: 'YOU WIN !',
data: { rank: 326 },
'points': OBJECT_ID,
'access_token': TOKEN
};
I get the error: {"message":"Unknown path components: \/points.win","type":"OAuthException","code":2500}
I do have a "Points" object and a "Win" action on my app interface (and a "Win A Point" story).
I don't really know what i am doing wrong, also i am not sure my OBJECT_ID is right, i found a value close to my app_id at the end of the sample url by clicking "Get the Code" (on the points object) > Code for object > inside the object=...url=.../<here>... and i used it here but i didn't find where it's clearly said Object_id: <value> on developer.facebook.com.
UPDATE: I think the only way to get an object ID is to create it thought the Object API, i am going to try this way, i'll keep you updated if it's works or not.
I have created the object through the Object API and it works fine !

Load a model manually with EmberData

I have an Ember app with a login form which returns the current user in JSON format after successful login.
Using createRecord sets the returned JSON attributes directly on the model. For instance, is_private becomes user.is_private, not user.get('isPrivate')?
How do I load the user model so that the attributes are set correctly and I don't have to re-fetch it using the id?
As of a few days ago in ember data 1.0 beta you can use pushPayload to load data directly into the store. For example if you get data pushed to your app through WebSockets (we use the Heroku add-on Pusher). You can call it on the store (source) directly and it will pass it through the appropriate serializer:
var postsJSON = {
posts: [
{id: 1, post_title: "Great post"}
]
}
this.store.pushPayload('post',postsJSON)
NOTE that it will not currently load a singular object (ie post: {id: 1, post_title:"First!"}) - you need to format it as plural with an array.
DS.RESTSerializer has pushPayload as well (source), in which case you need to pass it the store instead.
I highly encourage reading the source code before using, as it looks like the implementation of it will be revisited.
Supposedly, the official way to do this is using adapter.load, as described in this thread:
Loading Data
Previously, some features of the store, such as load(), assumed a
single adapter.
If you want to load data from your backend without the application
asking for it (for example, through a WebSockets stream), use this
API:
store.adapterForType(App.Person).load(store, App.Person, payload);
This API will also handle sideloaded and embedded data. We plan to add
a more convenient version of this API in the future.
But unfortunately, it doesn't handle sideloaded data, despite what the documentation claims. I personally use something like the following, which is based on how find(ID) is implemented:
var id = json["person"]["id"];
var store = DS.get("defaultStore");
var adapter = store.adapterForType(App.Person);
adapter.didFindRecord(store, App.Person, json, id);
var person = App.Person.find(id);
Note that this code assumes JSON in the same format that find(ID) expects to receive from the server, as documented in the RESTAdapter guide:
{
person: {
id: 1,
is_private: false,
projects: [3]
},
projects: [
{ id: 3, name: "FooReader" }
]
}
This will apply any transformations you've configured using keyForAttributeName (such as mapping is_private to isPrivate), and it will handle sideloaded records. I'm not sure if this is a best practice, but it works quite well.
how about store.push('user', userJSON)?
http://emberjs.com/guides/models/pushing-records-into-the-store/#toc_pushing-records
All answers above did not work for me.
What only worked for me was:
this.store.buildRecord(this.store.modelFor('person'), data.id, data)