Prevent Ember JSONAPISerializer from Sideloading - ember.js

I'm working on an Ember app that consumes an external API and I'm having trouble with my serializer.
My app is ingesting a user account but only cares about the very basics of the user account. The API is publishing much more data, which is causing trouble. Specifically, it is including a relationship to a model which I don't include in my Ember App (because it is domain-inappropriate).
I'm trying to configure my app such that it simply ignores the included and relationship information from the API, but even attempting to delete them from the response in the serializer's normalize hook isn't working. It keeps trying to look up the unwritten model and, obviously, failing. As well, I looked at using DS.EmbeddedRecordsMixin but that seems to still depend on having the related model implemented in my app, which I'm really hoping to avoid!
How do I get JSONAPISerializer to ignore relationships and prevent it from attempting to sideload data from the included object?
To better display my situation, here is an example payload:
{
"jsonapi": {
"version": "1.0"
},
"included": [
{
...references models my app doesn't have
}
],
"data": {
"type": "account",
"relationships": {
"permissions": {
"data": [
...references the included object
]
},
},
"id": "16",
"attributes": {
...this is the information I *do* care about
}
}
}
ETA:
My User model:
// app/models/account.js
export default Model.extend(Validations, {
birthdate: attr('date'),
email: attr('string'),
firstName: attr('string'),
lastName: attr('string'),
profile: belongsTo('profile')
}

Related

Ember Data relationships not resolved

I'm still learning ember.js and have run into a roadblock with ember data not resolving lookup relationships in models. I have one model 'site' that will be basically a lookup table for every other model to differentiate data based on location.
At this point, I'm doing something wrong or missing a key concept - probably both... (or maybe it's the wee hour!)
Site Model (i.e. the lookup table)
import DS from 'ember-data';
export default DS.Model.extend({
code: DS.attr(),
name: DS.attr(),
});
The site model would have a hasMany relationship to all my other models (will be about 12 when complete)
Associate Model
import DS from 'ember-data';
import { belongsTo } from 'ember-data/relationships';
export default DS.Model.extend({
site: belongsTo('site'),
last: DS.attr(),
first: DS.attr(),
active: DS.attr('boolean'),
fullName: Ember.computed('first', 'last', function() {
return `${this.get('first')} ${this.get('last')}`;
}),
});
The 'associate model' will also be a lookup along with 'site' in some other models.
I'm providing data via the JSON API spec but I'm not including the relationship data because as I understand it, ember data it should be pulling down the site data using the site id attribute.
{
"links": {
"self": "/maint/associates"
},
"data": [
{
"type": "associate",
"id": "1",
"attributes": {
"site": "6",
"last": "Yoder",
"first": "Steven",
"active": "1"
},
"links": {
"self": "/associates/1"
}
}
]
}
In my template file I'm referencing associate.site which gives me an error.
<(unknown mixin):ember431>
If I use associate.code or .name to match the site model, nothing will show in the template. The code from the 'site' table is the data I really want to displayed in the template.
So the obvious questions:
Am I wrong that Ember Data should be resolving this or do I need to
include the relationship in my API response?
I realize that my belongsTo in the 'associate' model only references
site while I want site.code, so how do I make that relationship
known or access the field in my 'associate' model?
I didn't include hasMany relationship in the 'site' model because
there would be many. Do I need to do an inverse relationship in
other models? Examples I've seen don't all show the hasMany
relationships setup.
When I look at the models in ember inspector the site field is not
included in the model. Even if I wasn't getting the correct data
should it still show up?
I like ember so far, just need to understand and get over this roadblock
Update: My backend JSON library would only generate relationship links based on the current spec which would be
"related": "/streams/1/site"
but ember data does call
"related": "/sites/1"
to resolve the relationship
So #Adam Cooper answer is correct if you generate links as he answered or if you can only generate the links based on the current specification.
If you're using the JSONAPIAdapter, which is the default, you want your response to look this:
{
"links": {
"self": "/maint/associates"
},
"data": [{
"type": "associate",
"id": "1",
"attributes": {
"last": "Yoder",
"first": "Steven",
"active": "1"
},
relationships: {
"site": {
"links": {
related: "/sites/6"
}
}
}
}]
}
That will allow Ember Data to look up the site via its relationship. Right now Ember is trying to access the site model which Ember Data can't populate hence the error you're getting. As an aside you could probably do with returning an actual boolean value for active too.

Ember isn't always loading belongsTo

I can't seem to workout how to load relationships properly in Ember. The user model only returns some of the time. If I refresh the page there seems to be a 50/50 chance the value will be null, or it will resolve correctly.
I understand in the route I'm returning a promise which is the server object (the belongsTo end of the user relationship), but how do I tell the route to wait for the user model to load before loading the page, or how do I tell ember to update the data on the page when it finally does load the user?
I've tried playing around with RSVP in the afterModel hook but haven't had any luck. There must be a obvious solution to this?
route
model(param) {
return this.store.findRecord('server', param.server_id);
},
server model
export default Model.extend(Validations, {
user: belongsTo('user'),
});
user model
export default Model.extend({
displayName: attr('string'),
servers: hasMany('server'),
});
component
export default Ember.Component.extend({});
component template
<div class="user-panel">
<ul class="user-details">
<li>owner:{{model.user.displayName}}</li>
</ul>
</div>
I've read a similar question here How to load belongsTo/hasMany relationships in route with EmberJS
But as I'm only returning a single object rather than an array I get Array Methods must be provided an Array thrown when trying any of the solutions
Server response
{
"data": {
"type": "server",
"id": "578aba694b08ce2310f36798",
"attributes": {
//removed
},
"relationships": {
"jobs": {
"data": [
{
"type": "jobs",
"id": "578aba694b08ce2310f3679a"
}
]
},
"user": {
"data": {
"type": "user",
"id": "57760677d04e0f11f4d3f7e5"
}
}
}
}
}
This should work out of the box! Not the waiting part, but the auto update.
Checkout this twiddle.
But if you want to wait for the model you can just enforce this in the afterModel hook:
afterModel(model) {
return get(model, 'user');
}

Converting backend json response to Ember store expected format

I am pretty new to ember and trying to do some POC's to fit our existing applications.
Using ember 1.13.12 and ember data 1.13.15
I have two models,
company.js
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
employee: DS.hasMany('employee',{async:true}),
});
employee.js
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
alias: DS.attr('string')
});
The serializers extend the JSONSerializer and sets the primarykey for both models and the option embedded always for employee model.
Backend json response for /employee/7, - this results in error - Ember.A(...) map not a function
{
"name": "abc"
"employee": {
"employeeId": 7,
"name": "employee7",
"alias": "e7"
}
}
Backend json response for /employees - this gets pushed to the ember store without issues
{
"name": "abc"
"employee": [
{
"employeeId": 1,
"name": "employee1",
"alias": "e1"
},
{
"employeeId": 7,
"name": "employee7",
"alias": "e7"
}
]
}
With the above response I faced two issues,
Not having an 'id' for the 'company' model to push to the store (Workaround ended up changing the backend response to have an 'id')
When I try getting a single employee say employee/7/ the json response from backend does not return as an array (Workaround added one of the normalize hook and added a line payload.employee = [payload.employee] and it worked)
Is there a way I can get past the above issues without changing the backend response and workarounds.

Ember Data not loading hasMany on store.find()

I currently have a model with two hasMany relationships as seen below:
Ember Model:
DS.Model.extend({
createdAt: DS.attr('date'),
updatedAt: DS.attr('date'),
name: DS.attr('string'),
address: DS.attr('string'),
city: DS.attr('string'),
state: DS.attr('string'),
zip: DS.attr('string'),
users: DS.hasMany('user',{async:true}),
templates: DS.hasMany('template',{async:true})
});
Using this model, I have new templates/controllers/etc setup to create new users and new templates. I can successfully save new/update existing organizations, but when I try to push objects into either users or templates, I lose what may already be in the other of the existing users or templates array.
I can see this is because my loading of the organization in the controller to create new records is not pulling in the other records, it pulls in it's own array, but not the other, for example this code on the new templates controller:
New Template Controller
organizations: function(){
return this.store.find('organization');
}.property(),
actions: {
createTemplate: function() {
var self = this;
console.log(self.get('organizations'));
}
}
Will show the templates in the console when attached to the record, but not the users. Vise versa, the same code on the new users controller does not show the templates it is pulling in but does show the users.
What can I do to get my find to return both arrays of relationships. They are both in the database, I can see them calling the rest api, but just not when they are found using ember.
I'm still pretty new with Ember, so any help would be greatly appreciated.
Thanks.
Edit
Sample JSON response from server
{
"organization": {
"id": 40,
"name": "Sample Business LLC",
"address": "1234 Fun Avenue",
"city": "Happytown",
"state": "NE",
"zip": "12345",
"users": [4,1],
"templates": [4,1],
"createdAt": "2014-02-18T23:10:08.466Z",
"updatedAt": "2014-02-18T23:10:08.466Z"}
},
"meta": {
"href": "http://server/organizations/40"
}
}

Ember Data: Automatically set belongsTo association

I am using Ember Data 1.0 (beta 1) and am somewhat confused by the default behavior of associations in ED.
Assume a Book model that has many (hasMany) chapters with each chapter belonging to (belongsTo) a book. My expectation was that the instances of a book's chapters property would automatically have a reference to the book instance through their belongsTo association, but this appears not to be the case. Is this indeed the default behavior in Ember Data or am I overlooking something?
If this is indeed the default behavior, does this mean that I need to create a custom serializer to accomplish this?
No ember-data will not do this for you but it should be possible to achieve. In both cases ember-data will sideload those properties. (In past versions you could setup a mapping so those would be embedded, but you no longer can do this) In your example you would have the following:
App.Book = DS.Model.extend({
chapters: DS.hasMany('Chapter')
});
App.Chapter= DS.Model.extend({
book: DS.belongsTo('Book')
});
Once those are setup ember-data by default will look for a data structured like this:
{
"book": {
"id": "1"
"chapters": ["1", "2", "3"]
},
"chapters": [
{
"id": "1",
"book": "1"
},
{
"id": "2",
"book": "1"
},
{
"id": "3",
"book": "1"
}
]
}
If your data is not in that format and you can not change it then you can extend the extractSingle or extractArray methods on the serializer for that type. At the bottom of this link you can find some more info on that. Also remeber it looks for it in camelcase so you may also need to normalize the json object as well.