Gotcha!… again.

So, it turns out that relying on the names of your constructors being the same in production as they are in development is a really bad idea. The reason is this: minifiers change all that crap! I know what you’re saying, “Duh, they’re supposed to, dufus.” Okay yeah so it slipped my mind for a second. Good thing I didn’t deploy without testing first! ; )

Specifically, I was writing a little ditty in CoffeeScript in Ruby on Rails and was getting some strange behavior only when I started up a production server. Data were getting inexplicably mangled beyond recognition, and I couldn’t find the source of the problem… after all, it worked great in development mode! So without further ado, here’s what happened:

Here’s a couple Backbone models:

class H.Models.User extends Backbone.Model

class H.Models.Household extends Backbone.Model

Here’s the constructors for those two models, after being compiled into javascript:

a = new H.Models.User
User {_queue: Backbone.BlockingQueue, cid: "c33", attributes: Object, _changing: false, _previousAttributes: Object}

a.constructor
function User() {
_ref = User.__super__.constructor.apply(this, arguments);
return _ref;
}

b = new H.Models.Household
Household {_queue: Backbone.BlockingQueue, cid: "c47", attributes: Object, _changing: false, _previousAttributes: Object}

b.constructor
function Household() {
_ref = Household.__super__.constructor.apply(this, arguments);
return _ref;
}

The names of the two constructors are User and Household. Makes sense, right? But the constructors get mangled into the same thing by the Uglifier gem:

// Dev Tools console
a = new H.Models.User
n {_queue: n.BlockingQueue, cid: "c7", attributes: Object, _changing: false, _previousAttributes: Object}

a.constructor
function n() {
return t = n.__super__.constructor.apply(this, arguments);
}

b = new H.Models.Household
n {_queue: n.BlockingQueue, cid: "c33", attributes: Object, _changing: false, _previousAttributes: Object}

b.constructor
function n() {
return t = n.__super__.constructor.apply(this, arguments);
}

Notice a.constructor.name === b.constructor.name. Oops. So yeah… don’t rely on them being User or whatever in any code. ; )