Create an associated model from JSON - ember.js

I have a server response that looks like:
comments: [
0: {
body: "test3",
created_at: "2013-06-27T22:27:47Z",
user: {
email: "test#test.com",
id: 1,
name: "Tester"
}
}
]
And ember models:
App.Comment = DS.Model.extend({
user: DS.belongsTo('App.User'),
body: DS.attr('string')
});
App.User = DS.Model.extend({
name: DS.attr('string'),
email: DS.attr('string'),
});
How do I create an ember user model from the server's response?

The solution if you're using rails active model serializers is to embed :ids, include: true:
app/serializers/comment_serializer.rb
class CommentSerializer < ActiveModel::Serializer
embed :ids, include: true
attributes :created_at, :body
has_one :user
end
Just like the readme for active_model_serializers says, this will produce:
{
"users":[
{
"id":1,
"name":"Tester",
"email":"test#test.com",
}
],
"comments":[
{
"event":"commented",
"created_at":"2013-06-27T22:27:47Z",
"body":"test3",
"user_id":1
}
]
}

Related

How can I create a record with a nested/embedded record in Ember Data?

How can I create a nested/embedded model when creating a record with Ember Data? Specifically, I want to create a post model with a nested/embedded model author. The following code gives me the error:
Error while processing route: index Assertion Failed: You cannot add a 'undefined' record to the 'post.author'. You can only add a 'author' record to this relationship. Error: Assertion Failed: You cannot add a 'undefined' record to the 'post.author'. You can only add a 'author' record to this relationship.
App.IndexRoute = Ember.Route.extend({
model: function() {
return this.store.createRecord('post', {
title: 'My first post',
body: 'lorem ipsum ...',
author: {
fullname: 'John Doe',
dob: '12/25/1999'
}
});
}
});
App.Post = DS.Model.extend({
title: DS.attr('string'),
body: DS.attr('string'),
author: DS.belongsTo('author')
});
App.Author = DS.Model.extend({
fullname: DS.attr('string'),
dob: DS.attr('string')
});
Any ideas on how to do this? I also created a demo on JSBin: http://emberjs.jsbin.com/depiyugixo/edit?html,js,console,output
Thanks!
Relationships need to be assigned to instantiated models, plain objects won't work.
App.IndexRoute = Ember.Route.extend({
model: function() {
return this.store.createRecord('post', {
title: 'My first post',
body: 'lorem ipsum ...',
author: this.store.createRecord('author', {
fullname: 'John Doe',
dob: '12/25/1999'
})
});
}

New model instance with hasMany relationship from form data [duplicate]

I am very new at Ember/ED/EmberFire so apologies if this is a trivial question. I am able to save records to Firebase but I am unable to specify relationships to those records in my controller. I am using
DEBUG: Ember : 1.10.0
DEBUG: Ember Data : 1.0.0-beta.12
DEBUG: Firebase : 2.2.3
DEBUG: EmberFire : 1.4.3
DEBUG: jQuery : 1.11.2
I have a model as such:
var Patient = DS.Model.extend({
lastName: DS.attr('string'),
firstName: DS.attr('string'),
encounters: DS.hasMany('encounter', {async: true})
});
var Encounter = DS.Model.extend({
dateOfEncounter: DS.attr('string'),
patient: DS.belongsTo('patient', {async: true})
});
I am simply trying to specify the patient that my newly created encounter object is associated with. This is my controller:
actions: {
registerEncounter: function() {
var newEncounter = this.store.createRecord('encounter', {
dateOfEncounter: this.get('dateOfEncounter'),
patient: this.store.find('patient', '-Jl8u8Tph_w4PMAXb9H_')
});
newEncounter.save();
this.setProperties({
dateOfEncounter: ''
});
}
}
I can successfully create the encounter record in Firebase, but there is no associated patient property. All I get is
https://github.com/firebase/emberfire/issues/232
this.store.find('patient', '-Jl8u8Tph_w4PMAXb9H_') returns a promise.
Try this:
this.store.find('patient', '-Jl8u8Tph_w4PMAXb9H_').then(function(pat) {
var newEncounter = this.store.createRecord('encounter', {
dateOfEncounter: this.get('dateOfEncounter'),
patient: pat
});
newEncounter.save();
});

ember how to display relationship property in template

I have a ember data model like this:
var attr = DS.attr,
hasMany = DS.hasMany,
belongsTo = DS.belongsTo;
App.Message = DS.Model.extend({
partner_pk: attr(),
message: attr(),
user: belongsTo('user', {async: true}),
inquiry: belongsTo('inquiry', {async: true}),
created_at: attr(),
updated_at: attr()
});
and route returning array of data like this:
App.TripMessagesRoute = Ember.Route.extend({
model: function(){
return this.store.find('message', {inquiry_id: 2});
}
})
My rest-api return data like this format:
{
"data": [
{
"id": 10,
"message": "this message is updated by ember.js",
"inquiry_id": 2,
"user_id": 1,
"created_at": "2014-08-05 14:20:46",
"updated_at": "2014-08-05 14:20:46"
},
{
"id": 17,
"message": "this is a test message by ember.js",
"inquiry_id": 2,
"user_id": 39,
"created_at": "2014-08-26 17:34:55",
}
]
}
in my template I am displaying the properties like this:
<script type="text/x-handlebars" data-template-name="trip/messages">
<h2>message is: {{message}}</h2> <!-- This works fine -->
<h2>User id: {{log user}}</h2> <!-- it gives null -->
<h2>User id: {{log user_id}}</h2> <!-- it gives undefined -->
</script>
My question is how do I display user_id in my template. Thanks in advance.
By default the property name in your Model definition should match the property being returned in your JSON.
Your choices are...
change your model to look like user_id: belongsTo('user', {async: true})
change your JSON to look like "user_id": 39
Add a MessageSerializer and change the object from user_id to user in the serializer.
You should then be able to put something like {{user.id}} in your template.

Ember Data - how to findBy with an associated hasMany

I have two objects User and Post. A user has many posts and a post belongs to a user.
How do I, within the user controller, use findBy or another method to get to a featured post with the posts array??
Here is how I implemented the UserController; however, the featuredPost computed property is coming back as undefined. Is this best approach? If so, what am I missing?
App.User = DS.Model.extend({
name: DS.attr('string'),
email: DS.attr('string'),
client: DS.belongsTo('App.Client', { async: true }),
posts: DS.hasMany('App.Post', { async: true })
});
App.Post = DS.Model.extend({
client: DS.belongsTo('App.Client', { async: true }),
user: DS.belongsTo('App.User', { async: true }),
title: DS.attr('string'),
body: DS.attr('string'),
isFeatured: DS.attr('boolean')
});
App.UserController = Ember.ObjectController.extend({
needs: ['post'],
posts: (function() {
return Ember.ArrayProxy.createWithMixins(Ember.SortableMixin, {
content: this.get('content.posts')
});
}).property('content.posts'),
featuredPost: (function() {
return this.get('content.posts').findBy('isFeatured', true)
}).property('content.featuredPost'),
});
Take a look at this: http://emberjs.com/api/#method_computed_filterBy
App.UserController = Ember.ObjectController.extend({
featuredPost: Ember.computed.filterBy('posts', 'isFeatured', true)
});
Also, in
featuredPost: (function() {
return this.get('content.posts').findBy('isFeatured', true);
}).property('content.featuredPost')//should be observing 'posts'
You are basically observing content.featuredPost but from what youve mentioned that property doesnt exist, the property you should be observing is 'posts'. This is a mistake that i made when i was learning ember too, so felt like pointing out. Also using content is optional, you can directly observe the model associated with controller.
Also From doc, findBy seems to return just first item that matches the passed value, not all of them. So to get first match it should be
App.UserController = Ember.ObjectController.extend({
featuredPost: function() {
return this.get('posts').findBy('isFeatured', true);
}.property('posts')//assuming user model hasMany relation to posts
});
Also I would go with the latest version of ember data and make following changes:
App.User = DS.Model.extend({
name: DS.attr('string'),
email: DS.attr('string'),
client: DS.belongsTo('client', { async: true }),
posts: DS.hasMany('post', { async: true })
});
App.Post = DS.Model.extend({
client: DS.belongsTo('client', { async: true }),
user: DS.belongsTo('user', { async: true }),
title: DS.attr('string'),
body: DS.attr('string'),
isFeatured: DS.attr('boolean')
});
This would be good read : https://github.com/emberjs/data/blob/master/TRANSITION.md
And here is a bare minimum working example : http://jsbin.com/disimilu/5/edit
Hope this helps.

Ember data alias model / Map JSON response

My server returns a JSON response like this:
{
artists: [{
id: "1",
first_name: "Foo",
last_name: "Bar"
}],
studios: [{
id: 1,
name: "Test",
// ...
artist_ids: ["1"]
}]
}
'artist' is in fact a User model but with a different name. How can I map artist to the User model? Maybe a bad explanation but if I rename the JSON response serverside to 'users' instead of 'artist' and use the models below everything works like I want. I simply want to use the name 'artist' instead of 'user', both server side and client side. Hope you guys understand what i mean.
App.Studio = DS.Model.extend
name: DS.attr 'string'
// ..
users: DS.hasMany 'App.User'
App.User = DS.Model.extend
firstName: DS.attr 'string'
lastName: DS.attr 'string'
studio: DS.belongsTo 'App.Studio'
I guess that the simplest thing to do would be something like artists: DS.hasMany 'App.User' but obviously this does not work.
First, I recommend using the latest Ember / EmberData, so relationships are defined like this:
App.Studio = DS.Model.extend({
name: DS.attr('string'),
// ..
users: DS.hasMany('user')
});
App.User = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
studio: DS.belongsTo('studio')
});
Next, I recommend using the ActiveModelAdapter if you are getting underscores in your response JSON:
App.ApplicationAdapter = DS.ActiveModelAdapter;
Finally, overriding typeForRoot and keyForRelationship in a custom serializer should fix your issue:
App.ApplicationSerializer = DS.ActiveModelSerializer.extend({
typeForRoot: function(root) {
if (root == 'artist' || root == 'artists') { root = 'user'; }
return this._super(root);
},
keyForRelationship: function(key, kind) {
if (key == 'users') { key = 'artists'; }
return this._super(key, kind);
}
});
Example JSBin
One last thing: you can even get rid of the custom keyForRelationship if you name the relationship artists in Studio:
App.Studio = DS.Model.extend({
name: DS.attr('string'),
// ..
artists: DS.hasMany('user')
});
Have you tried just creating an Artist model extended from User?
App.Artist = App.User.extend({})
I haven't tried it, but I suspect that might work.