Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

JsonSerializer's serialization for embedded has-many relationships includes too many records #576

Closed
wants to merge 2 commits into from

3 participants

@yipdw

When serializing a has-many relationship on a model object, DS.JSONSerializer serializes all records in all has-many relationships on that model object. Therefore, if a model has multiple embedded has-many relationships, the serialized form of that model object will contain the same set of records in each relationship.

This can be seen by adding another has-many relationship to the Post model in tests/integration/embedded/embedded_without_ids_test.js, not adding any code to add records to that relationship, adjusting the deepEqual assertions to expect empty arrays as the serialization result, and running the changed tests.

This pull request contains an implementation of the above test suite change as well as a proposed fix. All comments are, of course, welcome -- I'm still finding my way around the Ember Data codebase and tests.

@yipdw yipdw Demonstrate unwanted record sharing.
By adding a pingbacks relationship and not modifying it in any test, we
should end up with an empty array in all serialized Posts, i.e.

    {
        "post": {
            "comments": [
                {
                    "title": "Wouldn't a more lightweight...",
                    "user": null
                },
                {
                    "title": "This does not seem to reflect...",
                    "user": null
                }
            ],
            "pingbacks": [],
            "title": "A New MVC Framework in Under 100 Lines of Code"
        }
    }

However, what we get is

    {
        "post": {
            "comments": [
                {
                    "title": "Wouldn't a more lightweight...",
                    "user": null
                },
                {
                    "title": "This does not seem to reflect...",
                    "user": null
                }
            ],
            "pingbacks": [
                {
                    "title": "Wouldn't a more lightweight...",
                    "user": null
                },
                {
                    "title": "This does not seem to reflect...",
                    "user": null
                }
            ],
            "title": "A New MVC Framework in Under 100 Lines of Code"
        }
    }
54927ae
packages/ember-data/lib/serializers/json_serializer.js
((10 lines not shown))
- this.eachEmbeddedHasManyRecord(record, function(embeddedRecord) {
- array.push(this.serialize(embeddedRecord, { includeId: true }));
- }, this);
+ if (this.embeddedType(type, name)) {
+ if (target = get(record, name)) {
+ for(var i=0, l=get(target, 'length'); i<l; i++) {
@wagenet Owner
wagenet added a note

@yipdw Seems like it would be cleaner to use target.forEach here.

@yipdw
yipdw added a note

@wagenet: Sure thing; change applied.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@yipdw yipdw Consider relationship for embedded hasMany records.
When serializing a relationship, the previous algorithm serialized all
records in _all_ has-many relationships, not just all records for the
specified relationship.
adee9f4
@tomdale
Owner

Thanks! I merged this, plus improved it a bit in 6c2346d.

@tomdale tomdale closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 4, 2013
  1. @yipdw

    Demonstrate unwanted record sharing.

    yipdw authored
    By adding a pingbacks relationship and not modifying it in any test, we
    should end up with an empty array in all serialized Posts, i.e.
    
        {
            "post": {
                "comments": [
                    {
                        "title": "Wouldn't a more lightweight...",
                        "user": null
                    },
                    {
                        "title": "This does not seem to reflect...",
                        "user": null
                    }
                ],
                "pingbacks": [],
                "title": "A New MVC Framework in Under 100 Lines of Code"
            }
        }
    
    However, what we get is
    
        {
            "post": {
                "comments": [
                    {
                        "title": "Wouldn't a more lightweight...",
                        "user": null
                    },
                    {
                        "title": "This does not seem to reflect...",
                        "user": null
                    }
                ],
                "pingbacks": [
                    {
                        "title": "Wouldn't a more lightweight...",
                        "user": null
                    },
                    {
                        "title": "This does not seem to reflect...",
                        "user": null
                    }
                ],
                "title": "A New MVC Framework in Under 100 Lines of Code"
            }
        }
Commits on Jan 9, 2013
  1. @yipdw

    Consider relationship for embedded hasMany records.

    yipdw authored
    When serializing a relationship, the previous algorithm serialized all
    records in _all_ has-many relationships, not just all records for the
    specified relationship.
This page is out of date. Refresh to see the latest.
View
16 packages/ember-data/lib/serializers/json_serializer.js
@@ -110,11 +110,19 @@ DS.JSONSerializer = DS.Serializer.extend({
},
addHasMany: function(hash, record, key, relationship) {
- var array = [];
+ var type = record.constructor,
+ name = relationship.key,
+ array = [],
+ self = this,
+ target;
- this.eachEmbeddedHasManyRecord(record, function(embeddedRecord) {
- array.push(this.serialize(embeddedRecord, { includeId: true }));
- }, this);
+ if (this.embeddedType(type, name)) {
+ if (target = get(record, name)) {
+ target.forEach(function (record) {
+ array.push(self.serialize(record, { includeId: true }));
+ });
+ }
+ }
hash[key] = array;
},
View
19 packages/ember-data/tests/integration/embedded/embedded_without_ids_test.js
@@ -1,5 +1,5 @@
var store, Adapter, adapter;
-var Post, Comment, User;
+var Post, Comment, User, Pingback;
var attr = DS.attr;
module("Embedded Relationships Without IDs", {
@@ -15,9 +15,13 @@ module("Embedded Relationships Without IDs", {
user: DS.belongsTo(User)
});
+ Pingback = App.Pingback = DS.Model.extend({
+ });
+
Post = App.Post = DS.Model.extend({
title: attr('string'),
- comments: DS.hasMany(Comment)
+ comments: DS.hasMany(Comment),
+ pingbacks: DS.hasMany(Pingback)
});
Adapter = DS.RESTAdapter.extend();
@@ -27,7 +31,8 @@ module("Embedded Relationships Without IDs", {
});
Adapter.map(Post, {
- comments: { embedded: 'always' }
+ comments: { embedded: 'always' },
+ pingbacks: { embedded: 'always' }
});
adapter = Adapter.create();
@@ -167,7 +172,9 @@ asyncTest("Embedded hasMany relationships can be saved when embedded: always is
{
title: "This does not seem to reflect the Unix philosophy haha",
user: null
- }]
+ }],
+
+ pingbacks: []
}
});
@@ -265,7 +272,9 @@ asyncTest("Embedded records that contain embedded records can be saved", functio
user: {
name: "microuser"
}
- }]
+ }],
+
+ pingbacks: []
}
});
Something went wrong with that request. Please try again.