Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

recursive Rails style serialization for javascript objects (See related posts)

Have you ever wanted to post from your javascript program to a Rails app so that the params are available to your application in a properly nested hash? Prototype makes this easy for form elements with it's Form Serializer, but it makes no provision for standard javascript objects.

Suffer no longer. With the following code you can serialize arbitrarily nested objects (eg, the sort of thing you get when you parse a JSON statement), so that it is ready to be posted via http to a Rails app.

The original Rails recursive Javascript object serializer.

var serializer = {
 
  serialize : function(object) {
    var values = []; 
    var prefix = '';
    
    values = this.recursive_serialize(object, values, prefix);
    
    param_string = values.join('&');
    return param_string;
  },
  
  recursive_serialize : function(object, values, prefix) {
    for (key in object) {
      if (typeof object[key] == 'object') {
        
        if (prefix.length > 0) {
          prefix += '['+key+']';         
        } else {
          prefix += key;
        }
        
        values = this.recursive_serialize(object[key], values, prefix);
        
        prefixes = prefix.split('[');
        
        if (prefixes.length > 1) {
          prefix = prefixes.slice(0,prefixes.length-1).join('[');
        } else {
          prefix = prefixes[0];
        }
        
      } else {
        value = encodeURIComponent(object[key]);
        if (prefix.length > 0) {
          prefixed_key = prefix+'['+key+']'          
        } else {
          prefixed_key = key
        }
        prefixed_key = encodeURIComponent(prefixed_key);
        if (value) values.push(prefixed_key + '=' + value);
      }
    }
    return values;
  }
}


Usage:

payload = new Object;
payload.comment = new Object;
payload.comment.title = "The Title";
payload.comment.body = "The body of the post.";
post_string = serializer.serialize(payload);


Result:

comment%5Btitle%5D=The%20Title&comment%5Bbody%5D=The%20body%20of%20the%20post.


Which gives you this in Rails:

params[:comment] #=>
{:title => "The Title", :body => "The body of the post."}

Comments on this post

viniciuscb posts on Nov 01, 2006 at 12:21
Your code did not function properly when I used a more complex data structure, with arrays inside objects. Also, it serializes the user functions in the 'object' and 'array' objects. This makes bad behaviour when using some obtrusive javascript library, for instance Prototype. I send the code with my corrections, that seems to be working properly.

var serializer = {

serialize : function(object) {
var values = [];
var prefix = '';

values = this.recursive_serialize(object, values, prefix);

param_string = values.join('&');
return param_string;
},

recursive_serialize : function(object, values, prefix) {
var value;
var prefixed_key;
var child_prefix = '';
for (var key in object) {
if (typeof object[key] == 'object' || typeof object[key] == 'array') {

if (prefix.length > 0) {
child_prefix = prefix + '['+key+']';
} else {
child_prefix = key;
}

values = this.recursive_serialize(object[key], values, child_prefix);

} else if (typeof object[key] != 'function') {
value = encodeURIComponent(object[key]);
if (prefix.length > 0) {
prefixed_key = prefix+'['+key+']'
} else {
prefixed_key = key
}
prefixed_key = encodeURIComponent(prefixed_key);
if (value) values.push(prefixed_key + '=' + value);
}
}
return values;
}
}
viniciuscb posts on Nov 01, 2006 at 12:23
oops the code above indented

var serializer = {
 
  serialize : function(object) {
    var values = []; 
    var prefix = '';
    
    values = this.recursive_serialize(object, values, prefix);
    
    param_string = values.join('&');
    return param_string;
  },
  
  recursive_serialize : function(object, values, prefix) {
    var value;
    var prefixed_key;
    var child_prefix = '';
    for (var key in object) {
      if (typeof object[key] == 'object' || typeof object[key] == 'array') {
        
        if (prefix.length > 0) {
          child_prefix = prefix + '['+key+']';         
        } else {
          child_prefix = key;
        }
        
        values = this.recursive_serialize(object[key], values, child_prefix);
                
      } else if (typeof object[key] != 'function') {
        value = encodeURIComponent(object[key]);
        if (prefix.length > 0) {
          prefixed_key = prefix+'['+key+']'          
        } else {
          prefixed_key = key
        }
        prefixed_key = encodeURIComponent(prefixed_key);
        if (value) values.push(prefixed_key + '=' + value);
      }
    }
    return values;
  }
}
kludgebox posts on Nov 08, 2006 at 07:59
I also found it was reporting undefined object values as the string "undefined" ... alter this line:

} else if (typeof object[key] != 'function') {


to read:

} else if (typeof object[key] != 'function' && typeof object[key] != 'undefined') {


this way it will skip undefined values.

You need to create an account or log in to post comments to this site.


Click here to browse all 5140 code snippets

Related Posts