Skip to content

Collection._prepareModel validates stale attrs object if model has defaults #539

Closed
@lawnsea

Description

@lawnsea

I overrode the set method of one of my models to coerce values to Dates, but found that validation was failing when I tried to fetch the corresponding collection. This is because Collection._prepareModel validates the passed attributes rather than getting a fresh set from the model, but the Model constructor passes a new object to set if defaults is set. As a result, the changes made in set are not reflected in the original attrs object which is validated.

Relevant lines:
Model constructor (135-138)

if (defaults = this.defaults) {
    if (_.isFunction(defaults)) defaults = defaults.call(this);
    attributes = _.extend({}, defaults, attributes);
}

Collection._prepareModel (570-571)

model = new this.model(attrs, {collection: this});
if (model.validate && !model._performValidation(attrs, options)) model = false; 

I think doing attributes = _.extend(attributes, defaults, attributes); would work, but there's likely a better solution.

Test case:

var MyModel = Backbone.Model.extend({
    defaults: {
        theDate: null
    },

    validate: function (attributes) {
        if (!_.isDate(attributes.theDate)) {
            return 'theDate must be a date';
        }
    },

    set: function (attributes, options) {
        if (_.isNumber(attributes.theDate)) {
            attributes.theDate = new Date(attributes.theDate);
        }
        Backbone.Model.prototype.set.call(this, attributes, options);
    }
});

var model = new MyModel({ theDate: (new Date(1, 1, 2011)).getTime() });
console.log(model.get('theDate')); // Date {Sat Aug 04 1906 00:00:00 GMT-0500 (CST)}

var MyModelList = Backbone.Collection.extend({
    model: MyModel
});

var list = new MyModelList([{ theDate: (new Date(1, 1, 2011)).getTime() }]);
console.log(list.length); // 0!

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions