ember-data: how to get embedded json - javascript

My Json Data looks like this:
{"user":{"id":1,
"name":"bob",
"profile":{"id":1,
"forename":"Foo",
"surname":"Bar",
"user_id":1}}
My model looks like:
App.User = DS.Model.extend({
name: DS.attr('string'),
profile: DS.belongsTo('App.Profile')
});
and
App.Profile = DS.Model.extend({
forename: DS.attr('string'),
surname: DS.attr('string'),,
user: DS.belongsTo('App.User')
});
When I try to get {{user.name}}, it works fine. user.profile.forename doesnt work. I tried for my user model
DS.AuthenticatedRESTAdapter.map('App.User', {
profile: {embedded: true}
});
as well, but still doenst work. Any suggestions?

What is missing is configuring the serializer (used by the adapter) by calling its 'map' function:
App.MySerializer = DS.Serializer.extend({
init: function(){
this._super();
this.map(App.User, {
profile: {
embedded: 'load'
}
});
}
});
You can find a working example at JFiddle here.

Related

Error while processing route: home No model was found for 'App.undefined'

DEBUG: Ember : 1.7.1
DEBUG: Ember Data : 1.0.0-beta.12
DEBUG: Handlebars : 1.1.2
DEBUG: jQuery : 1.10.2
Having an issue with what I believe is the belongsTo attribute on my user model. (This happens on my other belongsTo attributes within my application as well). I have a Django backend which returns a response when I comment out the network: attribute.
{
email: "test#test.com",
first_name: "Test",
global_code: "daht64q691zy4k887ch",
global_id: "GBID-USER-dat64q6917zy4k887ch",
institution_gbid: "GBID-GINS-567j53ey0lojsu2kys",
institution_name: "Some University",
last_name: "Testing",
network: { },
view_policy: {
capability: "system:view",
description: "Anyone can view a user",
hold: true,
id: "daht64q691y4k887ch:system:view",
values: ""
}
}
Code for the User Model:
App.User = DS.Model.extend({
first_name: DS.attr('string'),
last_name: DS.attr('string'),
global_id: DS.attr('string'),
network: DS.belongsTo('basicgrouping')
}):
Code for Basic Grouping model:
App.Basicgrouping = DS.Model.extend({
global_id: DS.attr('string'),
name: DS.attr('string'),
gbid_code: function(){
return getGBIDCode(this.get('global_id'));
}.property('global_id')
});
Debugging ember-data I placed a console.log() within the following code:
relationshipsByName: Ember.computed(function() {
var map = Map.create();
this.eachComputedProperty(function(name, meta) {
console.log(name, meta);
if (meta.isRelationship) {
meta.key = name;
var relationship = relationshipFromMeta(this.store, meta);
relationship.type = typeForRelationshipMeta(this.store, meta);
map.set(name, relationship);
}
});
This seems to show that the type of the object that it belongs to is not being found (Basicgrouping) as it's returning App.undefined.
My theory is it may have something to do when parsing the server response and maybe the payload response. This also happens in other belongTo relationships in my code.
It turns out that there was a file that was overriding some of the DS. methods and causing an empty type to be sent. I was in the process of removing use of the shim but didn't know that it was being used.
Thanks the Bmacs from the ember community for the help debugging the issue.

Get one item from many using slug in Ember.js

I have these two models:
deomens.Artwork = DS.Model.extend({
title: DS.attr('string'),
slug: DS.attr('string'),
description: DS.attr('string'),
thumbnail: DS.attr('string'),
artwork: DS.attr('string'),
created_at: DS.attr('string'),
updated_at: DS.attr('string'),
options: DS.hasMany('option', {async: true}),
hasOptions: Ember.computed.gt('options.length',0)
});
deomens.Option = DS.Model.extend({
name: DS.attr('string'),
detail: DS.attr('string'),
artwork: DS.belongsTo('artwork')
});
I'm using the RESTAdapter like this:
deomens.Store = DS.Store.extend({
revision: 12,
adapter: DS.RESTAdapter.create({
namespace: 'deomens/public/api'
})
});
deomens.ArtworkSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
options: { embedded: 'always', serialize: 'ids', deserialize: 'records' }
}
});
Here is my router:
deomens.Router.map(function(){
this.resource('artworks');
this.resource('artwork', {path: '/view/:slug'});
});
And here are the two routes I've created:
deomens.ArtworksRoute = Ember.Route.extend({
model: function(){
return this.store.findAll('Artwork');
}
});
deomens.ArtworkRoute = Ember.Route.extend({
model: function(params){
//need to return a single item based on slug
//something like return this.store.find('Artwork', {slug: params.slug});
}
});
ArtworksRoute works fine - it returns all the artworks with their options.
However whenever I go to /view/artworkSlug, it fires up another GET request. So can I not get an item from already retrieved data? That's one question.
The second question - let's say if I make it fire up another GET request using:
return this.store.find('Artwork', {slug: params.slug});
it sends a GET request to the following URL:
/api/artworks?slug=artworkSlug
Can't I change this to something like this?
/api/view/slug
Nevermind the first question - it was a bad idea as someone landing on a specific artwork page, would not have all the artworks cached to find one.
As for the second question, I had to use return this.store.find('Artwork', params.slug); instead.

EmberJS: Fetch a Single Attribute of a Model After the Model is Fetched

I have two models, a User with many Messages:
App.Router.map(function() {
this.resource('user', { path: ':user_id' }, function () {
this.route('profile', { path: 'profile' });
this.resource('messages');
});
});
App.User = DS.Model.extend({
displayName: DS.attr('string'),
email: DS.attr('string'),
firstName: DS.attr('string'),
lastName: DS.attr('string'),
location: DS.attr('string'),
messages: DS.hasMany('message')
});
App.Message = DS.Model.extend({
user: DS.belongsTo('user'),
createdAt: DS.attr('date'),
updatedAt: DS.attr('date'),
fullText: DS.attr('string'),
subject: DS.attr('string'),
recipients: DS.attr('string')
});
Currently, I must load the entire model, including all messages associated with the user, when I perform a search for users.
What I'd like to do instead is:
Retrieve the user
Retrieve the messages of the user (when the user is selected)
I cannot find an easy way to do this in Ember. My best guess is call find in the route, possibly:
App.UserRoute = Ember.Route.extend({
model: function (params) {
var user = this.store.find('user', params.user_id);
this.store.find('message', { user: 3 });
return user;
}
}
But this generates the url /messages?user_id=3. What I'd like instead is something like /users/3/messages.
How do I query for messages associated with a user?
I think { async: true } is what you're looking for. See http://discuss.emberjs.com/t/what-is-an-async-relationship-async-true-vs-async-false/4107 for some discussion on what it is, and how to use it.
You would probably want to setup your model like this:
App.User = DS.Model.extend({
displayName: DS.attr('string'),
email: DS.attr('string'),
firstName: DS.attr('string'),
lastName: DS.attr('string'),
location: DS.attr('string'),
messages: DS.hasMany('message', { async: true } )
});
Then when your Handlebars template makes a request for {{myUser.messages}} (or {{myUser.messages.someProperty}} Ember Data will look at the User model, and note that the message id's (say, 5, 10, and 12). It will then look in the local datastore for messages 5, 10, and 12. If it has them, it will display them. If they're not present, it will then use the Adapter you've defined for Message (or if no adapter is defined the default RESTAdapter) to fetch these using an HTTP GET.
I believe it will make one request for each id (versus one request for all of them), but that's something I'm not 100% sure about.

Infinite Loop in Ember-Data clearRelationships?

Inquiry:
Can anybody tell me why I might be getting an infinite loop when attempting to delete an Ember-Data Model. Stepping through the crash, the issue appears to be in clearRelationships, but no matter how minimal I attempt to make the Model relationships I can't seem to get away from the infinite loop, without avoiding them all together.
Relevant Code:
//// Config
App = Ember.Application.create();
App.Adapter = DS.RESTAdapter.extend();
App.store = DS.Store.create({
revision: 11,
adapter: App.Adapter.create()
});
App.Router = Ember.Router.extend({});
App.Router.map(function() {
this.resource('main', { path: '/' });
});
//// Models
App.Scientist = DS.Model.extend({
name: DS.attr('string'),
tests: DS.hasMany('App.Tests'),
criteria: DS.belongsTo('App.Criteria')
});
App.Test = DS.Model.extend({
name: DS.attr('string'),
scientist: DS.belongsTo('App.Scientist'),
criteria: DS.belongsTo('App.Criteria')
});
App.Criteria = DS.Model.extend({
name: DS.attr('string'),
scientist: DS.belongsTo('App.Scientist'),
test: DS.belongsTo('App.Test'),
resources: DS.hasMany('App.Resource')
});
App.Resource = DS.Model.extend({
name: DS.attr('string'),
criteria: DS.belongsTo('App.Criteria')
});
//// Pre-Load Models
App.store.loadMany(App.Test,
[{id:'1', scientist_id:'1', name:'gravity', criteria_id:'2'},
{id:'2', scientist_id:'1', name:'not gravity', criteria_id:'3'}]);
App.store.load(App.Scientist,
{id:'1', name:'Bill', tests:['1', '2'], criteria_id:'1'});
App.store.load(App.Criteria,
{id:'1', name:'control', scientist_id:'1', test_id:null, resources:['1']});
App.store.loadMany(App.Criteria,
[{id:'2', name:'variation1', scientist_id:null, test_id:'1', resources:['2','3']},
{id:'3', name:'variation2', scientist_id:null, test_id:'2', resources:['4','5']}]);
App.store.loadMany(App.Resource,
[{id:'1', name:'resource1', criteria_id:'1'},
{id:'2', name:'resource2', criteria_id:'2'},
{id:'3', name:'resource3', criteria_id:'2'},
{id:'4', name:'resource4', criteria_id:'3'},
{id:'5', name:'resource5', criteria_id:'3'}]);
var filter = App.Test.filter(
function(model) { if (model.get('isLoaded') === true) { return model; } }
);
App.MainRoute = Ember.Route.extend({
setupController: function(controller, model) {
controller.set('tests', filter);
}
});
///// Controller
App.MainController = Ember.ArrayController.extend({
name: 'Main',
createTest: function() {
App.Test.createRecord();
App.store.commit();
},
removeTest: function(test) {
test.deleteRecord();
App.store.commit();
}
});
Steps to Reproduce:
http://jsfiddle.net/hilem/GMt7H/
1) Open Browser Console.
2) Run the fiddle.
3) Watch console as you hit remove on one of the list items.
Update 1 (8:44PM 1/27/2013)
Additional Context: This is using ember-1.0.0-pre.4.js && the latest commit of ember-data on master as of 1/27/2013. I also added a bit more to the example code above.
Update 2 (5:25PM 2/1/2013)
Bump! Issue still exists, there seems to be quite a few issues involving deleteRecord lately on github issue tracker that sound similar to my issue. Here's a link to my specific issue on the tracker:
https://github.com/emberjs/data/issues/671
It's a bug. This pull request on Github fixed it for me. https://github.com/emberjs/data/pull/715
I was having a similar issue. I had models like these
App.User = DS.Model.extend({
account: DS.belongsTo('App.Account'),
name: DS.attr('string')
});
App.Account = DS.Model.extend({
user: DS.belongsTo('App.User'),
type: DS.attr('string')
});
The recursion isn't actually happening in clearRelationships but in this section of the ember.js set method
var meta = obj[META_KEY], desc = meta && meta.descs[keyName],
isUnknown, currentValue;
if (desc) {
desc.set(obj, keyName, value);
} else {
....
}
when I deleted the User it tried to clearRelationships which calls set(this, "account", null) which eventually gets to the section above which calls set again and again and again.
I'm not sure the right way to fix this but I got it to work in my situation by removing the user belongsTo relationship on the account. so my new models look like this
App.User = DS.Model.extend({
account: DS.belongsTo('App.Account'),
name: DS.attr('string')
});
App.Account = DS.Model.extend({
// user: DS.belongsTo('App.User'),
type: DS.attr('string')
});

How do I load two models in one JSON request in Ember-data?

Using Ember-data and Ember.js, I'm trying to load two models with one JSON request. The models have a relationship analogous to this:
App.Person = DS.Model.extend({
name: DS.attr('string'),
dogs: DS.hasMany('App.Dog'),
});
App.Dog = DS.Model.extend({
name: DS.attr('string'),
owner: DS.belongsTo('App.Person'),
});
My server is sending JSON like this:
{
"dog": {
"id": 1,
"name": "Fido",
"owner": {
"id": 1,
"name": "John Smith",
"dogs": [1]
}
}
}
…And yet, Ember-data still sends a request (using findQuery) to my server trying to get the owner JSON.
I have a jsFiddle set up that demonstrates it here. To watch the problem happen, you'll need to go to this link to activate the route/template:
http://fiddle.jshell.net/6kQ8s/2/show/#/dog/1
I haven't defined findQuery() in my adapter on purpose because I shouldn't need that to get data that I have already sent… Right?
Does anyone know what I'm doing wrong here?
I'm doing the following (using ember-data revision 8)
App.Dog = DS.Model.extend({
name: DS.attr('string'),
owner: DS.belongsTo('App.Person', { embedded: true }),
});
Additionally, I have to tell the serializer to load a mapping for this relation.
Though it's not required, I'm using my own DS.Serializer subclass. At initialisation
time the serializer loads a mapping for the Person class, which specifies that
embedded relationships should be loaded.
App.WOSerializer = DS.Serializer.extend({
init: function(){
this._super();
this.map(App.Dog, {
person: {
embedded: 'load'
}
});
});
Edit by question asker:
The serializer needed to be initialized in the adapter.
App.adapter = DS.Adapter.create({
// ...
serializer: App.WOSerializer.create()
});
Try use embedded property.
App.Dog = DS.Model.extend({
name: DS.attr('string'),
owner: DS.belongsTo('App.Person', { embedded: true }),
});

Categories

Resources