1
//Setup:
Ember: 1.3.2
Handlebars: 1.3.0
jQuery: 2.0.0
-----------------
MongoDB (_id's, embedded data)

I have been attempting to get a self many to many relationship like this:

//Model:
App.Post = DS.Model.extend({
    title: DS.attr('string'),
    content: DS.attr('string'),
    links: DS.hasMany('App.Post'), 
});

Links should be embedded as id's for (hopefully) obvious reasons.

After a couple of days digging around I have managed to get the app to serialise and submit the data correctly via RESTAdapter, the code I am using looks like this:

//Controller:
App.PostController = Ember.ObjectController.extend({
    actions: {
        addRelated: function(related) {
            var links = this.content.get('links').pushObject(related);
            this.content.save();
        }
    }
});

//Store:
App.Store = DS.Store.extend({
    revision: 12,
    adapter: DS.RESTAdapter.extend({
        url: '/admin/api',
        serializer: DS.RESTSerializer.extend({
            primaryKey: function(type) {
                return '_id';
            },
            addHasMany: function(hash, record, key, relationship) {
                if (/_ids$/.test(key)) {
                    hash[key] = [];
                    record.get(this.pluralize(key.replace(/_ids$/, ''))).forEach(function(post) {
                        hash[key].push(post.get('id'));
                    });
                }
                return hash;
            }
        })
    });
});

From what I can gather the serializer is expecting data in the form

{post: {...}, links: [{...},{...}]}

But since the link is of type post, I would rather not create an entire App.Links model if possible.

So can I map links to posts? As in

{post: {...}, posts: [{...},{...}]}

I tried adding a deserializeHasMany but it didn't get called when using App.Post.find()

I am guessing I would need to write a custom extract function that takes link_ids and extracts the posts into the record from it?

Joe Swann
  • 31
  • 4

1 Answers1

0

pI haven't test this but would say:

You should change your model to look like this:

App.Post = DS.Model.extend({
    title: DS.attr('string'),
    content: DS.attr('string'),
    links: DS.hasMany('post'), //changed 
});

Your JSON should be in the format:

{"posts": [{ "id":3 ... post item .... "links":[3,10]} { "id":4... post item .... "links":[4,11]}]} 

All links must be included in the JSON unless already loaded.

My understanding is that you should not have to override the RESTAdapter and RESTSerializer as this should work out of the box - if it doesn't I'd first check ajax and capitalization.

TrevTheDev
  • 2,616
  • 2
  • 18
  • 36
  • Hi Trev, okay so I changed the json to use Posts (I didn't change _id to id because I'm using mongodb). The error now is `DS.hasMany('post')` created the following errors: Assertion failed: You specified a hasMany (post) on App.Post but post was not found. & Assertion failed: Trying to sideload links on App.Post but the type doesn't exist. I should also note I can't use embedded posts because that seems to result in infinite recursion errors, not to mention I just want to store id's anyway – Joe Swann Feb 19 '14 at 20:19
  • 1
    Hi Joe, ember is very particular about the format of your JSON and if this is not 100% it will not work. I've not used so cannot comment on mongodb however my sense it ember expects "id". also links must include all of the ids in an array as shown. In ember data there is a function called extractSingle that if you step through it on load you can see the relationship between primaryTypeName and type.typeKey which should match up if things are working nicely. If you don't want ember to check if links exist during load you can set the async flag eg: links: DS.hasMany('post', {async: true}) – TrevTheDev Feb 20 '14 at 01:04
  • Hey Trev, Thanks for that. I'm not at home right now so I will have to have a look at extractSingle later. I used http://dbushell.com/2013/04/25/ember-data-and-mongodb/ as a reference for working with mongodb hence setting the primary key and addExtractMany function. I think given the links are actually linking to id's that are already loaded (App.Post relies on them) async shouldn't matter should it? Currently it seems to be submitting the links just fine and the json the backend returns on load looks like `"links":["530407c6b1af9f4f1e8b4567"],` (see the link for how the _id's get handled). – Joe Swann Feb 20 '14 at 02:13
  • Actually at one point it was also submitting `"link_ids":["530407c6b1af9f4f1e8b4567","530407c6b1af9f4f1e8b4569"]` since *_ids seems to how ember data handles non embedded posts, I'm not sure which of these two I should be working with next though. The original problem is ember data seems to want to only `POST` link_ids via the child not the parent, see the first answer on http://stackoverflow.com/questions/15138219/ember-data-saving-a-relationship – Joe Swann Feb 20 '14 at 02:16
  • Joe I feel your pain - I spent way too many hours getting this to work for me - also because ember data has changed so much the doco is often outdated and shows the wrong way to do things now. e.g. I also initially defined my relationships as 'App.Post' which is now wrong but after stepping through extractSingle saw that things did not match up. – TrevTheDev Feb 20 '14 at 02:49
  • Haha well thanks for your patience, I'll try extractSingle next and see if it is even attempting to do anything meaningful.. – Joe Swann Feb 20 '14 at 06:54
  • Sorry to keep bugging you, I tried logging values passing through extractSingle but it doesn't seem to be getting called at all. On a hunch I tried extractMany and that is getting called. Should I be trying to get extractSingle to call or am I on the right track? – Joe Swann Feb 20 '14 at 09:23
  • Nope extractMany is for an array and extractSingle is for one item - so you are on the right track. – TrevTheDev Feb 20 '14 at 11:06