Migrating adapter mapping to latest ember-data - ember.js

I have a CouchDB based backend. As in every document-based store, deeply nested properties are first-class citizens. That means, a nested property does not necessarily refer to an independent object. Often, a nested property is just used to structure complex objects, without implying any belongsTo or hasMany relationship. One direct consequence of this is that nested "objects" (which are not really objects) have no IDs.
Since ember-data does not directly supported nested properties, until now I have been modelling these objects using belongsTo relationships, with success. This is the data structure that I am receiving from my backend:
{
"agents": [
{
"_id": "04ef35dd-6ab9-492f-ada6-0d4f4de9610a",
"genproperties": {
"playable-url": null
},
"org_id": 11653,
"outputs": {
"exten": null,
"extension": "c4facb9d-850c-4b67-9592-b467129fa9d4",
"jumpIfBusy": null,
"jumpIfNoAnswer": null,
"nextnode": "a1e00fb9-8604-4119-8515-3a31a36c60d1",
"startnode": null
},
"properties": {
"agent_status": "online",
"allowed_portlets": [
"xxx-portlet",
"yyy-portlet",
"zzz-portlet",
"uuu-portlet",
"ppp-portlet"
],
"default_portlet": "xxx-portlet",
"email": "a.b#c.com",
"enabled_portlets": [
"xxx-portlet",
"yyy-portlet",
"zzz-portlet",
"uuu-portlet",
],
"first_name": "John",
"main-service": null,
"name": "John Ferdinand Smith",
"portlet_language": "en",
"pov-org": null,
"services": {
"associated": {}
},
"surname1": "Ferdinand",
"surname2": "Smith"
},
"type": "wav-user"
},
...
]
}
This is my adapter:
App.Adapter = DS.RESTAdapter.extend({
bulkCommit: false,
namespace: App.config.API_NAMESPACE,
url: mynamespace.apiUrl,
serializer: App.MetaRESTSerializer.create(),
ajax: function(url, type, hash) {
var ajaxPromise = this._super(url, type, hash);
if (App.config.DEBUG_ADAPTER) { console.log('>>>>> REQUESTED > %s:%s > hash=%o ajaxPromise=%o', type, url, hash, ajaxPromise); }
ajaxPromise.then(function(json){
if (App.config.DEBUG_ADAPTER) { console.log('>>>>> RECEIVED > %s:%s > %o', type, url, json); }
});
return ajaxPromise;
}
});
These are my current model definitions:
App.NodeOutputs = DS.Model.extend({
startnode : DS.attr('string'),
jumpIfBusy : DS.attr('string'),
jumpIfNoAnswer : DS.attr('string'),
nextnode : DS.attr('string'),
extension : DS.attr('string'),
exten : DS.attr('string'),
});
App.NodeMixin = Ember.Mixin.create({
nodeType : DS.attr('string'),
nodeSubtype : DS.attr('string'),
outputs : DS.belongsTo('App.NodeOutputs'),
});
App.Adapter.map('App.GenProperties', {
playableUrl : {key: 'playable-url'},
});
App.AgentProperties = App.CommonProperties.extend({
default_portlet : DS.attr('string'),
allowed_portlets : DS.attr('rawTransform'),
portlet_language : DS.attr('string'),
verified_emails : DS.attr('rawTransform'),
email : DS.attr('string'),
agent_status : DS.attr('string'),
});
App.Agent = DS.Model.extend(App.NodeMixin, {
properties : DS.belongsTo('App.AgentProperties'),
genproperties : DS.belongsTo('App.GenProperties'),
});
And these are my mappings:
App.Adapter.map('App.NodeOutputs', {
startnode : {key: 'startnode'},
jumpIfBusy : {key: 'jumpIfBusy'},
jumpIfNoAnswer : {key: 'jumpIfNoAnswer'},
nextnode : {key: 'nextnode'},
extension : {key: 'extension'},
exten : {key: 'exten'},
});
App.Adapter.map('App.Agent', {
nodeType : { key: 'type' },
nodeSubtype : { key: 'subtype' },
outputs : { embedded: 'always' },
properties : { embedded: 'always' }
genproperties : { embedded: 'always' }
});
That was working perfectly with ember-data#0.0.14. Now I am moving to ember-data#1.0.0-beta.3, and it seems the DS.RESTAdapter.map is no longer supported.
I have taken a look at these resources:
the migration guide
and the documentation (hidden on the methods tab)
also a related question
But I still have no idea how to accomplish these two simple tasks:
how to define simple key mappings, like type -> nodeType (json -> ember model)
how to specify that a belongsTo is embedded: 'always'
Question : Is there some sample code showcasing key mappings and embedded properties for the latest ember-data? Does it support embedded properties without IDs?
I have over 30 mappings to migrate, so I'd better make sure to understand what I am doing before starting with it.

Related

How do I declare a `type` key on a polymorphic relationship in Ember.js?

I'm trying to learn ember.js and I have a problem with trying to use the DS.FixtureAdapter with mock data. Whenever I try to access the store I get an Ember error of:
Error while processing route: exercises Assertion Failed: Ember Data expected a number or string to represent the record(s) in the pictureExercises relationship instead it found an object. If this is a polymorphic relationship please specify a type key. If this is an embedded relationship please include the DS.EmbeddedRecordsMixin* and specify the pictureExercises property in your serializer's attrs hash.
Looking at the ember data section in the ember inspector I can see all the top level exercise data is loaded correctly, the PictureExercises and VideoExercises are not.
How do I declare a type key on a polymorphic relationship in Ember.js?
I'm at a total loss and any help would be greatly appreciated. Thanks for your time.
//Create application store
Gymbo.ApplicationAdapter = DS.FixtureAdapter;
//Set up models and relationships
Gymbo.Exercise = DS.Model.extend({
//id: DS.attr("number"), /*Ember will error if id is in model* /
name: DS.attr("string"),
description: DS.attr("string"),
pictureExercises: DS.hasMany("pictureExercise", {async: true }),
videoExercises: DS.hasMany("videoExercise", { async: true })
});
Gymbo.PictureExercise = DS.Model.extend({
//id: DS.attr("number"),
exerciseId: DS.attr("number"),
mimeType: DS.attr("string"),
picFilePath: DS.attr("string"),
picName: DS.attr("string"),
exercise: DS.belongsTo("exercise")
});
Gymbo.VideoExercise = DS.Model.extend({
//id: DS.attr("number"),
exerciseId: DS.attr("number"),
videoName: DS.attr("string"),
videoFilePath: DS.attr("string"),
videoType: DS.attr("string"),
exercise: DS.belongsTo("exercise")
});
//UsersRoute
Gymbo.ExercisesRoute = Ember.Route.extend({
model: function () {
return this.store.find("exercise");
}
});
//MOCK DATA
Gymbo.Exercise.reopenClass({
FIXTURES:
[
{
"id": 101,
"name": "Exercise 1",
"description": "Description here",
"pictureExercises": [
{
"id": 106,
"exerciseId": 101,
"mimeType": "PNG",
"picFilePath": "images\\strength",
"picName": "s001"
},
{
"id": 107,
"exerciseId": 101,
"mimeType": "JPG",
"picFilePath": "images\\strength",
"picName": s002
}
],
"videoExercises": [
{
"id": 101,
"exerciseId": 101,
"videoName": "Test",
"videoFilePath": "Video\\strength",
"videoType": "mp4"
}
]
},
{
"id": 102,
//Data removed for brevity.....
}
]
});

Is there any example for reflexive relation?

I am trying iterate json response which more likely mentioned below and I want achieve this model through reflexive relation.
{
folders : [
{
id : 1,
folders [ { id : 1, folders : [] } ]
},
{
id : 2,
folders : [{ id : 1, folders : [ {id:1 , folders : [] }] }]
}
]
}
I here is my try
children: DS.hasMany('folders', {inverse: 'parent'}),
parent: DS.belongsTo('folders', {inverse: 'children'})
But does't work at all . is there any example ?
I have a similar structure for nested categories modeled like this
In my models/category.js
export default DS.Model.extend({
name: DS.attr('string'),
description: DS.attr('string'),
master: DS.belongsTo('category', {inverse: null})
});
Then in my routes/products.js I define the model hook like this
model: function() {
return {
products: this.store.findAll('product'),
categories: this.store.findAll('category')
};
}
From controllers/products.js I have access to categories and their master categories like this
var categories = this.get('model').categories;
for (var i=0; i < categories.get('length'); i++) {
var master = categories.objectAt(i).get('master').get('id');
It seems that ember takes care of everything in the background somehow.

Ember-data JSON structure

I have 5 models in some relations:
App.Service = DS.Model.extend({
name: DS.attr('string'),
service_prices: DS.hasMany('servicePrice')
});
App.ServicePrice = DS.Model.extend({
unit_price: DS.attr('number'),
qty_unit: DS.belongsTo('qtyUnit'),
service: DS.belongsTo('service'),
partner:DS.belongsTo('partner')
});
App.Partner = DS.Model.extend({
"name": DS.attr('string')
});
App.QtyUnit = DS.Model.extend(Ember.Validations.Mixin, {
name: DS.attr('string'),
});
App.Order = DS.Model.extend({
service: DS.belongsTo('service'),
unit_price: DS.attr('numeric'),
qty_unit:DS.belongsTo('qtyUnit')
});
I try to load an order with the following JSON:
var order = {
"order" : {"id":1,"service":1,"qty_unit":4,"unit_price":10},
"service":[{"id":1,"name":"ENG-GER","service_prices":[1,2]}],
"servicePrices":[
{"id":1,"qty_unit":4,"unit_price":3,"partner":1},
{"id":2,"qty_unit":5,"unit_price":4,"partner":1}
],
"qtyUnits":[
{"id":4,"name":"character"},
{"id":5,"name":"word"},
{"id":6,"name":"sentence"}
],
"partner":[
{"id":1,"name":"Jessie Bains"}
]
};
But im getting the following error:
Error while loading route: TypeError: Cannot read property 'deserialize' of undefined
Is my Json wrong structured?
Here is the JsBin:
http://jsbin.com/finahuna/12/edit
When requesting records, the relationships in the json should be plural (services, partners)
var order = {
"order" : {"id":1,"service":1,"qty_unit":4,"unit_price":10},
"services":[{"id":1,"name":"ENG-GER","service_prices":[1,2]}],
"servicePrices":[
{"id":1,"qty_unit":4,"unit_price":3,"partner":1},
{"id":2,"qty_unit":5,"unit_price":4,"partner":1}
],
"qtyUnits":[
{"id":4,"name":"character"},
{"id":5,"name":"word"}
],
"partners":[
{"id":1,"name":"Jessie Bains"}
]
};
Additionally your jsbin isn't working per say because:
services and qtyUnits didn't exist in the scope (possibly you debugging)
return Ember.RSVP.hash({
order:store.find('order',1),
services: store.all('service'),
qtyUnits: store.all('qtyUnit')
});
If your controller has an object backing it is needs to extend ObjectController not Controller
App.IndexController = Ember.ObjectController.extend({
});
Example: http://jsbin.com/wimoz/1/edit

How to write Ember model for tree type json

I am very new to ember, can any one tell me how to write ember model for json show below. I searched lot but couldn't come up with any solution
{id:1, name: "A", children: [
{ id:1, name: "A1" },
{ id:2, name: "A2" },
{
id:3, name: "A3", children: [
{
id:1, name: "A31", children: [
{ id:1, name: "A311" },
{ id:2, name: "A312" },
]
},
]
},
]
Thanks
Have you already tried something like the following? I have not worked with ember data yet, but i imagine it to work like this:
App.Person = DS.Model.extend({
id : DS.attr("number"),
name : DS.attr("string"),
children : DS.hasMany("App.Person"),
parent : DS.belongsTo("App.Person")
});
Somehow I figure out the solution after a long time. I am answering this question because it may help others
here is the json data I have used
{"parent":[
{"id":1, "name":"A", "children_ids":[1,2]}
],
"children":[
{"id":1, "name":"A1", "children_ids":[3,4]},
{"id":2, "name":"A2", "children_ids":[5]},
{"id":3, "name":"A11"},
{"id":4, "name":"A12"},
{"id":5, "name":"A21"}
]
}
Ember model
App.Parent= DS.Model.extend({
name: DS.attr('string'),
children: DS.hasMany('App.Children')
});
App.Children = DS.Model.extend({
name: DS.attr('string'),
children: DS.hasMany('App.Children')
});
Don't forget to make plural of children is children
DS.RESTAdapter.configure(
"plurals",{
children:"children"
}
)

ember data one-to-one association returns undefined

I have these two resources:
App.Users = DS.Model.extend({
first_name: DS.attr('string'),
last_name: DS.attr('string'),
email: DS.attr('string'),
userprofile: DS.belongsTo('App.Userprofiles', {embedded:true}),
fullName: function() {
return this.get('first_name') + ' ' + this.get('last_name');
}.property('first_name', 'last_name'),
didLoad: function() {
console.log('Developer model loaded', this);
}
});
App.Userprofiles = DS.Model.extend({
company: DS.attr('string'),
user: DS.belongsTo('App.Developers'),
didLoad: function() {
console.log('Developer Profile model loaded', this);
}
})
These are my view and controller:
App.UserInfoController = Ember.ObjectController.extend({
content: App.store.find(App.Users, 1),
}).create();
App.UserInfoView = Ember.View.extend({
controller: App.UserInfoController,
contentBinding: 'controller.content'
});
This a sample response for a user from my API
{
"email": "foo#gmail.com",
"first_name": "George",
"id": "1",
"last_name": "Eracleous",
"resource_uri": "/api/v1/users/1/",
"userprofile": {
"company": "bar",
"id": "1",
"resource_uri": "/api/v1/userprofiles/1/",
"user": "/api/v1/users/1/"
}
}
The user object is loaded correctly but when I try to do get("userprofile") I get null. Does anybody know what I am doing wrong?
In order to load embedded related objects you have to configure the serializer used by the adapter, by calling its 'map' function. The only way I know to do this is by subclassing the serializer and add an 'init' function to it, where you make the necessary calls to map. For every embedded relationship of every model class you will have to do a call to 'map'. This applies to to-one and to-many relationships. Make sure to configure your adapter to use this serializer.
For an example see my answer to a previous question.
You can also check out this example online.
As mentioned in the comment, instead of subclassing the serializer and calling its map() function in the initialiser you can directly call map() on the adapter class. As an example, here is an excerpt of my own code doing this.
WO.RESTAdapter.map(App.Category, {
resourceTypes: {
embedded: 'load'
}
});
WO.RESTAdapter.map(App.Resource, {
resourceType: {
embedded: 'load'
}
});
WO.RESTAdapter.map(App.Reservation, {
resource: {
embedded: 'load'
},
user: {
embedded: 'load'
}
});
App.serializer = App.WOSerializer.create();
App.store = DS.Store.create({
revision: 10,
adapter: WO.RESTAdapter.create({
namespace: "cgi-bin/WebObjects/Reserve.woa/ra",
serializer: App.serializer
}),
serializer: App.serializer,
adapterForType: function(type){
return this.get('adapter');
}
});