What I'm Trying:
Persist a new record but for some reason the request payload is empty even though the record has data.
Here's a fiddle: http://jsfiddle.net/brancusi/m8VrB/16/
(Disregard the firebase, it's just there so we can inspect the request payload on save.)
Explanation:
You will notice that when you save the record, the request payload is empty.
Ideally the request payload would look something like this:
{
"inventory": {
"entry_time": "2014-02-05",
"client_id": 1,
"user_id": 1,
"product_stock_levels": [
{
"product_id": 1,
"quantity": 2
},
{
"product_id": 2,
"quantity": 0
},
{
"product_id": 3,
"quantity": 8
}
]
}
}
Notes:
This only seems to be a problem when it's a new record. Updating existing records send the correct payload.
You are expecting ember data to embed relationships in a model on save as default. This is not the default behavior.
You could define relationships as being embedded per model. But there is no support for embedded record feature anymore as stated here: https://github.com/emberjs/data/blob/master/TRANSITION.md I am not sure if basic embedded record features still work with latest version of ember data. But you define a record as embedded like this:
App.InventorySerializer = DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
productStockLevels: {embedded: 'always'}
}
});
Because core team stopped support for this embedded records feature and it is very basic I would recommend you to use EmbbededAdapter or EmbeddedMixin if you need support for embedded records. You find them here: https://github.com/pixelhandler/ember-data-extensions
But as Ember Data EmbeddedAdapter is not stable yet. Perhaps you should consider not to embedded records to reduce complexity if you are flexible in defining the api.
Related
I currently have a response like so from my API:
{
"data": [{
"attributes": {
"customer_name": "The Name",
},
"id": 1,
"relationships": {
"tasks": {
"data": [{
"attributes": {
"name": "The task",
},
]
}
},
"type": "customer"
}
]
}
And Ember loads the model correctly. However, when I try and consume the computed property the relationship creates, Ember initiates an OPTIONS and subsequent GET request for each item in the relationship.
I haven't worked with these kinds of relationships before so this may be the expected behaviour but I'm a bit confused.
If it is going to do a request for each one, why bother sending the items as part of the original model via a relationship at all? Why not just do a normal model retrieval which would probably be much quicker.
It seems really wasteful so I suspect I'm not handling or understanding something correctly, I'd appreciate any insight.
This is expected behavior for what you are doing (accessing a hasMany relationship). In your example, the tasks do not exist in Ember Data's store so when trying to access them Ember Data is smart enough to fetch them for you from your API. In doing so, it sends out the OPTIONS and GET requests to retrieve them. The OPTIONS request is simply a preflight request.
If you wanted to work with this particular model and its tasks (or other hasMany relationship models) without making so many network requests, you could fetch both simultaneously by requesting them with an include assuming you're using an adapter that allows it (i.e., supports the JSON API spec) and your API does too:
// for example, fetching a post with its comments (hasMany relationship)
this.store.findRecord('post', params.post_id, { include: 'comments' } );
Doing so should return the model and its tasks in one network request. For further reading, I'd checkout Ember's guide on Relationships.
I’m running into an issue with the REST Adapter/Serializer and EmbeddedRecordsMixin, specifically my app needs to be able to sideload an model’s parent record in create/POST responses, and that parent model contains the child record embedded in a hasMany array. This is resulting in “You cannot update the id index of an InternalModel once set.” errors. heres a simplified version of the JSON structure my api is returning:
// POST /child-model response
{
"childModel": {
"id": 1,
"foo": "Bar"
},
"parentModel": {
"id": 2,
"children": [
{
"id": 1,
"foo": "Bar"
}
]
}
}
Is there any way to allow this type of response? Essentially I want ember-data to just treat the embedded child record as just an "update" to the record that was just created, where it is just using it to make the association between it and the parent record.
I am trying to create an organisations-table component, which will display a list of organisations, and the user for which each organisation belongs. I pass the model for the organisations into the component via an organisations.hbs template, which results in the following response from the server:
{
"organisations": [
{
"id": 0,
"name": "Org0",
"user": 1
},
{
"id": 1,
"name": "Org1",
"user": 2
},
{
"id": 2,
"name": "Org2",
"user": 2
}
]
}
In order to display the username for each user, the component then makes its own call to the server querying against the id for each of the users.
Is this the correct approach? My understanding is that components are supposed to be isolated by design, only aware of the data passed into them, but in this example, the component is sending its own requests to the server for the additional data.
I have created this ember twiddle to hopefully give an idea of the structure of the app (comments welcome!).
Thanks in advance
The component itself has nothing to do with the calls, { async: true } means that the relationship won't be fetched unless it is "needed".
Needed in this case being the organisation.user.username in your component's template.
Keep in mind that model in your case is an array of DS.Model objects that have relationships.
I'd like Ember (and Data) to request models from an API endpoint, but transform the raw data into models so that Ember can use it transparently.
The problem
We load in data via a number of API endpoints when the page loads. We also push data to the page via Pusher. In an effort to consolidate the transforming of raw data into a single location we've decided to put that logic on the client. When we push new data to the page, we have a utility method that transforms that data into an Interaction record.
Now, we need to also transform the raw data that the server passes to the page via AJAX request. It needs to pass through the same utility method, but I'm not sure where to intercept the response from the API so that I can properly transform the data. Where should I be looking, and what methods are at my disposal?
The raw data will be different based on the type of information it is, but here's a single example:
{
"created_at": "Wed May 01 18:32:43 +0000 2013",
"id": 329664697345384448,
"id_str": "329664697345384448",
"text": "#steveWINton true dat",
"user": {
"created_at": "Thu Feb 14 13:07:51 +0000 2008",
"id": 13470142,
"id_str": "13470142",
"name": "uo\u0287u\u0131\u028d\u01dd\u028c\u01dd\u0287s",
"screen_name": "NOTsteveWINton"
}
}
And it needs to be converted into the following format:
Social.Interaction = DS.Model.extend({
native_id: DS.attr("string"),
screen_name: DS.attr("string"),
name: DS.attr("string"),
text: DS.attr("string")
});
When the page loads, we're passing in a list of interaction IDs. Ember will then sideload the full data by hitting the interactions API endpoint. That part will not change from the way it currently works.
What we want is to be able to pass raw data to the page from the interactions endpoint rather than the "final" version of the model.
just had surgery, so i am short answer guy right now. You'll want to create a custom serializer, possibly per type.
See: https://github.com/emberjs/data/blob/master/TRANSITION.md
Could you simply poll for this using vanilla $.ajax and do a push after you finish the "transform" you mention above?
var json = do_something_to_transform_it_here();
store.serializerFor('interaction').pushSinglePayload(store, 'interaction', json);
I'm new to Ember, and am having a problem I'm not seeing duplicated anywhere else so I'm sure I'm doing something silly. I have these models:
App.User = DS.Model.extend({
username: DS.attr("string"),
userId: DS.attr("number"),
modules: DS.hasMany("App.Module")
});
App.Module = DS.Model.extend({
moduleId: DS.attr("number"),
name: DS.attr("string")
});
Note that my Module model is simply a container that a User can have a few of, and many users might share the same modules - they're actually represented by an Enum on the server. As such, the backend does not have a mapping of Module > Users, so I've left the DS.ownedBy or DS.hasMany out of App.Module. I have, however, tried my test with a "users: DS.hasMany('App.User')" in there as well, with the same result. If it turns out to be necessary, I could maintain such a mapping, but I have no other reason for doing so right now, so it would be a bit unfortunate to be forced to add such a table to my database.
I'm using Ember.Auth for authentication, and when my app loads up and I log in, the server requests (as expected):
users/nathan?authToken=<token>
The result is also as I think it should be, according to the ember data docs:
{
"user": {
"username": "nathan",
"user_id": 1,
"module_ids": [1,2]
},
"modules": [
{"module_id": 1, "name": "Account Settings"},
{"module_id": 2, "name": "Manage Websites"}
]
}
I'm then testing in the Chrome console with:
App.Auth.get("user").get("modules");
or
App.User.find("nathan").get("modules");
and in both cases, Ember makes a request to my server to get the data for Modules 1 and 2. If I repeat the same request, it doesn't go back to the server again, so it is storing the result properly that time, it's simply the sideload that it's ignoring.
I'm using ember-1.0.0-rc4 with ember-data-0.13.
In your sideload response, module_id should be id.
(or you can configure ember-data to use module_id, but formatting the server response should be the easier way?)
--- edit for explanation ---
I'm not sure the original REST call is "working perfectly". Without the id. ember-data does see the two modules that your originally sideloaded, but it sees no id, so it does not know that they are modules 1 and 2 respectively. By default (changeable), ember-data expects the id to be called id; your module_id (and user_id) are just treated as regular properties.
On your next API call (to /modules?ids[]=1&ids[]=2 presumably), ember-data silently assumes that, since your requested two modules, and two modules came back, they should be the two that you requested. Try sending back this
{
"modules": [
{"module_id": 3, "name": "Foo module"},
{"module_id": 4, "name": "Bar module"}
]
}
for the request /modules?ids[]=1&ids[]=2, you will still get your "successful" observation.
Try App.Module.find(1).get('name') with the module_id-response - you will get undefined; now try it with the id-response, and you will get Account settings as expected.
Have you configured your RestAdapter to sideload modules?
Like this:
DS.RESTAdapter.configure('App.Module', {
sideloadsAs: 'modules'
});