Skip to content

Instantly share code, notes, and snippets.

@trydionel
Created November 28, 2010 16:47
Show Gist options
  • Save trydionel/719080 to your computer and use it in GitHub Desktop.
Save trydionel/719080 to your computer and use it in GitHub Desktop.
Makes Backbone.js play nicely with default Rails setup
//
// Backbone.Rails.js
//
// Makes Backbone.js play nicely with the default Rails setup, i.e.,
// no need to set
// ActiveRecord::Base.include_root_in_json = false
// and build all of your models directly from `params` rather than
// `params[:model]`.
//
// Load this file after backbone.js and before your application JS.
//
Backbone.RailsJSON = {
// In order to properly wrap/unwrap Rails JSON data, we need to specify
// what key the object will be wrapped with.
_name : function() {
if (!this.name) throw new Error("A 'name' property must be specified");
return this.name;
},
// A test to indicate whether the given object is wrapped.
isWrapped : function(object) {
return (object.hasOwnProperty(this._name()) &&
(typeof(object[this._name()]) == "object"));
},
// Extracts the object's wrapped attributes.
unwrappedAttributes : function(object) {
return object[this._name()];
},
// Wraps the model's attributes under the supplied key.
wrappedAttributes : function() {
var object = new Object;
object[this._name()] = _.clone(this.attributes);
return object;
},
// Sets up the new model's internal state so that it matches the
// expected format. Should be called early in the model's constructor.
maybeUnwrap : function(args) {
if (this.isWrapped(args)) {
this.set(this.unwrappedAttributes(args), { silent: true });
this.unset(this._name(), { silent: true });
this._previousAttributes = _.clone(this.attributes);
}
}
};
_.extend(Backbone.Model.prototype, Backbone.RailsJSON, {
// This is called on all models coming in from a remote server.
// Unwraps the given response from the default Rails format.
parse : function(resp) {
return this.unwrappedAttributes(resp);
},
// This is called just before a model is persisted to a remote server.
// Wraps the model's attributes into a Rails-friendly format.
toJSON : function() {
return this.wrappedAttributes();
},
// A new default initializer which handles data directly from Rails as
// well as unnested data.
initialize : function(args) {
this.maybeUnwrap(args);
}
});
@bernat
Copy link

bernat commented Feb 23, 2011

Hello, I'm always getting the error "A name must be specified".
Is there any place where you wrote the documentation for this code? I'm trying to find the best way to use backbone with a rails app. Could you give me any advice? Thanks!

@trydionel
Copy link
Author

Hey bernat,

No, there's not a bit of documentation for this -- it's just a snippet I hacked together one weekend. It sounds like you just need to add a name attribute (which should be the key the JSON will be nested under) to your model:
var Widget = Backbone.Model.extend({
name: 'widget'
});

One thing to watch out for: since Backbone.js doesn't provide a create callback, I've had to add a default initializer which actually unwraps the JSON. If you override initialize in your model, you'll need to call this.maybeUnwrap(args) early in the new method.

Jeff

@panupan
Copy link

panupan commented Mar 16, 2011

Thanks, just what I needed!

@cybercent
Copy link

Thanks!

@dmix
Copy link

dmix commented Mar 24, 2011

thanks worked great

@dmix
Copy link

dmix commented Mar 24, 2011

this should be moved to a repo so it can be searched/contributed to.

@drewda
Copy link

drewda commented Mar 26, 2012

I just tried upgrading to Backbone 0.9.2 and now I'm getting this error: Uncaught TypeError: Cannot call method 'hasOwnProperty' of undefined. Anyone have a fix to suggest?

@thenickcox
Copy link

@drewda, your comment was 11 months ago, but I ran into this, too. My fix was to give it an || {} when it was asking for args in case args was undefined. Hope that helps anyone who gets here from Google.

@macool
Copy link

macool commented Jun 3, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment