Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nested attributes don't save and fetch as expected #3

Closed
toddself opened this issue Dec 20, 2013 · 3 comments
Closed

Nested attributes don't save and fetch as expected #3

toddself opened this issue Dec 20, 2013 · 3 comments

Comments

@toddself
Copy link
Contributor

I could be doing it wrong, but I would expect the following to work:

var Backbone = require('backbone');
var assert = require('assert');

var InnerModel = Backbone.Model.extend({
   urlRoot: '/innermodel'
});
InnerModel.prototype.sync = require('backbone-orm').sync(InnerModel);

var OuterModel = Backbone.Model.extend({
    urlRoot: 'mongodb://localhost:27017/testModel',
    schema: {
        innerModel: function(){
            return ['hasOne', InnerModel, {embed: true}];
        }
    }
});
OuterModel.prototype.sync = require('backbone-mongo').sync(OuterModel);

var om = new OuterModel({foo: 'bar', innerModel: new InnerModel({bar: 'baz'})});
om.save(function(err, om){
    if(err) return err;
    var om2 = new OuterModel({id: om.id});
    om2.fetch(function(om2){
       assert.deepEqual(om2.get('innerModel').attributes, om.get('innerModel').attributes);
    });
});

Errors out with:

TypeError: Cannot call method 'get' of null
    at repl:5:23
    at /Users/todd/src/conde/fauxpilot/node_modules/backbone-mongo/node_modules/backbone-orm/lib/utils.js:108:16
    at Object.success (/Users/todd/src/conde/fauxpilot/node_modules/backbone-mongo/node_modules/backbone-orm/lib/utils.js:92:18)
    at /Users/todd/src/conde/fauxpilot/node_modules/backbone-mongo/node_modules/backbone-orm/lib/extensions/model.js:407:66
    at /Users/todd/src/conde/fauxpilot/node_modules/backbone-mongo/node_modules/backbone-orm/lib/utils.js:108:16
    at success (/Users/todd/src/conde/fauxpilot/node_modules/backbone-mongo/node_modules/backbone-orm/lib/utils.js:92:18)
    at Object.options.success (/Users/todd/src/conde/fauxpilot/node_modules/backbone/backbone.js:433:22)
    at /Users/todd/src/conde/fauxpilot/node_modules/backbone-mongo/lib/sync.js:77:26
    at /Users/todd/src/conde/fauxpilot/node_modules/backbone-mongo/node_modules/backbone-orm/lib/cursor.js:236:22
    at QueryCache.module.exports.QueryCache.set

Because om2.get('innerModel') is null. Expected it to be the innerModel instance generated when om was generated.

It looks like since toJSON doesn't handle nested models correctly, the create method on line 63 of src/sync.coffee returns no data for the nested attribute.

@toddself
Copy link
Contributor Author

Or is there another way this is supposed to work? Should I be providing some sort of extra template? The examples are pretty light when it comes to saving/fetching nested models.

kmalakoff added a commit that referenced this issue Dec 23, 2013
@kmalakoff
Copy link
Member

Hello!

I've taken a look at your code and see that there are some conventions that need to be followed (some undocumented):

  1. Add callbacks are of the form "(err, result) ->" - that means "fetch(function(om2) {})" should be "fetch(function(err, om2) {})"

  2. The naming convention for models are:

    a) urls are underscored, pluralized: "/innermodel" should be "/inner_models"

    b) relationships are also underscored, but either pluralized or singularized depending on the relationship plurality: "innerModel" should be "inner_model"

  3. Because the embedded relationship is stored on the OuterModel, the relationship should be "belongsTo" instead of "hasOne".

Other things

  1. Instead of using a url on the InnerModel, you could add a property 'model_name: "InnerModel"' to it (with CoffeeScript in Node, model_name and url are optional).

  2. The function around a relationship is only necessary for breaking dependency cycles so "innerModel: function(){return [...]}" could be simplified to "inner_model: [...]"

  3. We typically don't use the fetch mechanic, but findOne:

  OuterModel.findOne om.id, (err, om3) ->
    assert.deepEqual(om3.get('inner_model').attributes, om.get('inner_model').attributes)

You can find a working version of your code here. Also, I will update the documentation to make the conventions more clear.

Just let me know if you have any more problems.

@toddself
Copy link
Contributor Author

@kmalakoff omg thank you so much for going through this! I'm going to go over it and implement the changes :)

Hope you had an excellent holiday!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants