How to create records that links to each other?


#1

hi,

in a web forum a thread has a title plus a bunch of posts. A post has a content and belongs to a thread. Like this:

App.Thread = DS.Model.extend({
    title: DS.attr('string'),
    posts: DS.hasMany('post', {async: true})
});

App.Post = DS.Model.extend({
    content: DS.attr('string'),
    thread: DS.belongsTo('thread', {async: true})
});

Alice goes to the forum and starts a new thread; she is presented with two input boxes, one for the title (of her thread) and one for the content (of the first post of the thread). When she’s happy, she hits the “post!” button for her thread to go live.

On the background, the ember squirrel has some work to do (in the save action of the NewThread route):

  1. create a thread record
  2. create a post record
  3. assign the newly created post record to the hasMany relationship of the thread record
  4. assign the newly created thread record to the belongsTo relationship of the post record
  5. save the thread record, sending it over the wire to the datastore in the backend
  6. save the post record as well.

My question is: how to code this list of steps in the save action? Though I feel I have a fair understanding of what needs to be done, I fail to see how ember wants this to be coded without fighting the framework.


#2

I think the order is:

  1. Create a thread record
  2. Create a post record
  3. Save the thread record so now you have the id assigned by the server
  4. Assign the thread record to the belongsTo relationship of the post record
  5. Save the post record so now you have the id assigned by the backend
  6. Assign the post record to the hasMany relationship of the thread record

Here is some code:

...
save: function() {
    // create the records
    var thread = this.store.createRecord('thread', { title: this.get('tittle') });
    var post = this.store.createRecord('post', { content: this.get('content') });
    var _this = this;

    // save the thread
    thread.save().then(function() {
        // now thread has the id
        post.set('thread', thread);

        // save the post
        post.save().then(function() {
            // the hasMany relationship is defined as `async: true` so you
            // have to use `.then()` to access it because `thread.get('posts')`
            // returns a promise
            thread.get('posts').then(function(posts) {
                // add the post to the thread.posts relationship
                posts.pushObject(post);

                // I think the following line is not necessary because
                // thread.posts property is not saved on the server. If you do
                // a this.store.find('thread', ...) to find this thread you get
                // the posts filled with the saved posts that belong to it
                thread.save();

                // finally you can transition or do anything you want after the process
                _this.transitionToRoute('thread.view', thread); // or whatever...
            });
        });
    });
}
...

I’m new to Ember so I don’t know if this code or aproach is correct so any correction is welcome.

PS: sorry my english


#3

Thanks a lot franip, that’s really helpful.

What I was missing, that you point out in your comments in the code, is that you need your backend on the server to assign an id to an object before you can stick that object as “participating” to whatever relationship.

You write:

I think the following line is not necessary because thread.posts property is not saved on the server […]

can you elaborate on that? Do you mean that relationships only “live” on the client, and are never sent to the server?


#4

I think this is not necessary.

As you have a thread with many posts you may have a threads table and a posts table. The posts table should have a foreign key named thread (or thread_id) but you don’t have a posts key in the threads table. This is the reason to save the post after creating the thread (so you have the thread’s id) and not need to save the thread after including the post on the hasMany property.

As you say this relationship lives on the client and when you make a this.store.find('thread') is when you receive from the backend the posts ids that belong to each thread.

I don’t know if I have explained it well but I’m on vacancies without a computer and it’s difficult to me to write on the mobile :frowning:


#5

that makes sense, thanks.