EmberJS; Can't create record with relationships - ember.js

I've a got User, Chat and Message model to create chat functionality in our app.
User:
messages: DS.hasMany 'message'
chat: DS.hasMany 'chat'
Chat:
users: DS.hasMany 'user'
messages: DS.hasMany 'message'
Message:
user: DS.belongsTo 'user'
chat: DS.belongsTo 'chat'
message: DS.attr 'string'
In this situation I already have a chat and a user object and what I'm trying to do is create a message in this chat which belongs to the user sending it.
I'm using the following to do so:
controller = Ember.ObjectController.extend Ember.Evented,
needs: 'application'
app: Ember.computed.alias 'controllers.application'
actions:
sendMessage: ->
content = Ember.$('.new-message input').val()
message = #store.createRecord 'message', message: content
message.set 'user', #get 'app.model.user'
message.set 'chat', #get 'model'
message.save().then =>
console.log "done"
But it results in the following error:
Uncaught Error: Assertion Failed: Cannot call get with 'isEmpty' on an undefined object
Two things that make the problem disappear:
Removing the message.set 'chat', #get 'model' line
Creating a message in the database (it works if it's not the first message being created)

Related

ember data 1.13.8 and ember cli mirage confusion

This is my Ember inspector info tab:
I am using ember-cli-mirage and I'm facing issue here.
I am not able to get belongsTo relationship of a model. When I do car.get('user'), I get a promise in result which gets fullfilled but the value is always null.
My user model
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('String'),
car: DS.belongsTo('car',{async: true})
});
My car model
import DS from 'ember-data';
export default DS.Model.extend({
color: DS.attr('String'),
user: DS.belongsTo('user',{async: true})
});
my mirage/config
this.get('/cars',function(db,request) {
var qp = request.queryParams.searchString.toLowerCase();
return {
cars: db.cars.where({'color':qp}),
users: db.users
};
});
I get the list of cars with search color but I don't get the user.
it returns a promise which when fullfilled gives null.
Since I am using ember-data 1.13.8
I tried using this Mirage working with json but then I get error
datum model is not defined error so i guess new json api is not my issue for some reason my ember data uses old json format and original config works.
this.get('/cars', function(db, request) {
return {
data: db.cars.map(attrs => (
{type: 'cars', id: attrs.id, attributes: attrs }
))
};
})
My cars route look like this
model: function(params) {
self = this;
if(!params){
return [];
}
return this.store.findQuery('car',params);
},
I tried
return this.store.findQuery('car',params).then(function(item){
console.log(item.get('user'));
});
but i still got console.log //undefined
I can see user_id in my json returned.
SOLUTION:
found the issue i was saving relationship as user_id = user.id. It should be user=user.id
SOLUTION: found the issue i was saving relationship as user_id = user.id. It should be user=user.id

Ember Uncaught Error: Attempted to handle event `didSetProperty`

I am getting this error and it seems to be when I destroy the session on my "auth" logic. I have read everything I can find and it seems to be something to do with the values of the object that is being destroyed, but I've tried everything I have found and no luck. If anyone could point me in the right direction to a solution I would greatly appreciate it.
Error
Uncaught Error: Attempted to handle event didSetProperty on while in state root.deleted.saved. Called with {name: email, oldValue: undefined, originalValue: undefined, value: test#test.com}.
Controller
App.ApplicationController = Ember.ObjectController.extend
actions:
signOut: ->
#get('model').destroyRecord().then =>
$.removeCookie 'apiKey'
#set 'model', #store.createRecord 'session'
#transitionToRoute 'sign-in'
, ->
#transitionToRoute 'sign-in'
Route
App.ApplicationRoute = Ember.Route.extend
model: ->
if !$.cookie 'apiKey'
#store.createRecord 'session'
else
#store.find('session', 'current').then (session)->
session
Session Model
App.Session = DS.Model.extend
access_token: DS.attr()
email: DS.attr()
password: DS.attr()
isLoggedIn: Ember.computed.notEmpty 'access_token'
user: DS.belongsTo 'user', embedded: 'always'
App.SessionSerializer = DS.ActiveModelSerializer.extend DS.EmbeddedRecordsMixin,
attrs: user: embedded: 'always'
This is a bit late, sorry.
When the promise to destroy the model is resolved, something is being set on the model - session record in this case. Please note the #get('model').destroyRecord() command is followed by the #set 'model' command.
That is why the error message has while in state root.deleted.saved.

Store promise resolved in template but not in controller

I have a select box with a list of users that I get from the store. I have a method on the controller where I try to get an initial user for the selectbox. No matter what I do I can't seem to get any user record to resolve on the method but the users show up fine in the selectbox. Can someone explain what I'm missing? Thank you in advance for the help.
Controller:
App.TodoModuleController = Ember.ObjectController.extend
users: Em.computed -> #store.findAll 'user'
selectedUser: Em.computed 'users', ->
#get('users').objectAt(1)
# There are 4 users in the db. Just using 1 for a test.
# I also tried
# #get('users').then (users)->
# users.objectAt(1)
selectedUserDidChange: Em.observer 'selectedUser', ->
if #get 'selectedUser' then #assignUser()
assignUser: ->
model = #get 'model'
model.set 'assigneeId', #get('selectedUser').get('id')
unless model.save()
console.log 'Error: TodoModuleController.assignUser'
Template:
{{view Em.Select content=users selection=selectedUser optionValuePath='content.id' optionLabelPath='content.firstName'}}
SOLUTION (thanks to Hrishi):
Todo Model:
App.Todo = DS.Model.extend
text: DS.attr 'string'
assignee: DS.belongsTo 'user', inverse: null
Todo Controller:
App.TodoModuleController = Ember.ObjectController.extend
users: Em.computed -> #store.findAll 'user'
assignedUserDidChange: Em.observer 'assignee', ->
if #get 'assignee' then #assignNewUser()
assignNewUser: ->
unless #get('model').save()
console.log 'Error: TodoModuleController.assignUser'
Select Box:
{{view Em.Select content=users selection=assignee optionValuePath='content.id' optionLabelPath='content.firstName'}}
Computed properties are not computed until someone (in your case, the template) tries to access them, in other words, they are computed lazily. Since the template tries to access them, the users array will get populated and you can see it on the page when you click on your select box. The way I would do this would be to put an attribute on the model called assignee and bind the view's selection directly to that.

Ember.js Model - Custom Errors

I'm getting a list of courses from the server and I need to handle different kind of custom errors.
This is how I set the model and how I catch the error, the problem is that I can't send a custom message for the error:
App.CoursesRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('course').then(function(response) {
return response;
}, function(error) {
// need to retrieve error message
});
}
});
This is the model for the Courses
App.Course = DS.Model.extend({
name: attr('string'),
teachers: attr('string')
});
This is de JSON that matches the courses model
{"courses":[{"name":"My Course","teachers":"2"},{"name":"Other Course","teachers":"3"}]}
I've tried many things like creating a Model for Errors and sending a JSON like this but nothing works...
App.Error = DS.Model.extend({
message: attr('string')
});
{"error":[{"message":"No courses found"}]}

Ember.js Many to many relationships. How to access data

We're working on a messaging system which will allow a user to submit a message to many social media accounts, which would result in a post to each account. In our application we have Accounts, Messages, and Posts. A Message is a single instance of my content which can then be sent as a Post.
Accounts can have many messages.
Messages can be tied to many Accounts.
Messages can have many Posts.
Posts belong to Messages.
We Model the data like so:
Social.Account = DS.Model.extend({
username: DS.attr('string'),
messages: DS.hasMany('Social.Message')
});
Social.Message = DS.Model.extend({
user_id: DS.attr('number'),
text: DS.attr('string'),
accounts: DS.hasMany('Social.Account'),
posts: DS.hasMany('Social.Post')
});
Social.Post = DS.Model.extend({
created: DS.attr('date'),
text: DS.attr('string'),
message: DS.belongsTo('Social.Message')
});
and FIXTURE data would look like this:
Social.Account.FIXTURES = [{
id: 1,
username: "commadelimited",
messages: [1, 2]
}];
Social.Message.FIXTURES = [{
id: 1,
user_id: 1,
text: 'This is message #1 sent by account #1',
accounts: [1],
posts: [1]
}, {
id: 2,
user_id: 1,
text: 'This is message #2 sent by account #1',
accounts: [1],
posts: [2]
}];
Social.Post.FIXTURES = [{
id: 1,
created: "5 minutes ago",
text: 'This is post #1 sent by account #1, tied to message #1'
}, {
id: 1,
created: "5 minutes ago",
text: 'This is post #2 sent by account #1, tied to message #2'
}];
Even though in our system a Message can result in man Posts, as far as the UI is concerned Messages are a 1 to 1 relationship.
I'm having trouble thinking about how to output the resulting Post when I have to start by looping over the Message first. This code outputs the message correctly, but I need to output the post instead.
{{#each messages in messages}}
<article>
<time>{{post.ts}}</time>
<div class="post-content">
<h2>{{post.text}}</h2>
</div>
</article>
{{/each}}
I've tried {{#each messages in messages.posts}} and it's nothing. Within the each loop I've outputting {{message}} within the loop which returns <Social.Message:ember391:1>. I can access the Post data in the console with this statement
Social.Account.find().objectAt(0).get('messages').objectAt(0).get('posts')
which returns an object of the correct type.
So, how do I get at the Post array for each Message?
So, how do I get at the Post array for each Message?
You can access the post array via the posts property of each message. So in handlebars:
{{#each message in messages}}
<p>Message: {{message}}</p>
<p>Message posts: {{message.posts}}</p>
{{#each post in message.posts}}
<article>
<time>{{post.ts}}</time>
<div class="post-content">
<h2>{{post.text}}</h2>
</div>
</article>
{{/each}}
{{/each}}
My example might be a bit more "finished" than you want but since I know you are working w/ a django backend ... here is the entire m2m setup (using ember.js and the django-rest-framework)
First up -the django models
class Tag(models.Model):
description = models.CharField(max_length=200)
class Session(models.Model):
name = models.CharField(max_length=150)
tags = models.ManyToManyField(Tag)
The basic "find all" and "find each tag" urls
url(r'^/sessions/$', views.SessionList.as_view()),
url(r'^/sessions/(?P<session_pk>\d+)/tags/$', views.TagBySessionList.as_view()),
The django views (django-rest-framework enabled if you will)
from rest_framework import generics
class SessionList(generics.ListCreateAPIView):
model = Session
serializer_class = SessionSerializer
class TagBySessionList(generics.ListCreateAPIView):
model = Tag
serializer_class = TagSerializer
def get_queryset(self):
session_pk = self.kwargs.get('session_pk', None)
if session_pk is not None:
return Tag.objects.filter(session__pk=session_pk)
return []
Now the django-rest-framework serializer to get the REST api setup
from rest_framework import serializers
class SessionSerializer(serializers.ModelSerializer):
tags = serializers.ManyPrimaryKeyRelatedField()
class Meta:
model = Session
fields = ('id', 'name', 'tags')
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ('id', 'description')
Next up -the ember-data models (notice -no fixture adapter here, real REST api calls)
CodeCamp.Session = DS.Model.extend({
name: DS.attr('string'),
tags: DS.hasMany('CodeCamp.Tag')
});
CodeCamp.Tag = DS.Model.extend({
description: DS.attr('string')
});
The root element that simply loads the parent element (basic find all)
CodeCamp.SessionsRoute = Ember.Route.extend({
model: function() {
return CodeCamp.Session.find();
}
});
(no need to ask for the m2m here as the DjangoRESTAdapter takes care of that given the endpoint above)
The handlebars template that does show the parent and each tag under it (m2m each working)
{{#each session in controller}}
{{session.name}}<br />
{{#each tag in session.tags}}
{{tag.description}}<br />
{{/each}}
{{/each}}