Unless I’m missing something, the default rails from_json and from_xml methods don’t work with data that have associated objects. Here are routines that work for some simple examples I’ve tested. I placed this code in vendor/rails/activerecord/lib/active_record/base.rb within the ActiveRecord::Base class, but there might be a better place to put it.
def self.from_hash( hash ) h = hash.dup h.each do |key,value| case value.class.to_s when 'Array' h[key].map! { |e| Object.const_get(key.camelize.singularize).from_hash e } when 'Hash' h[key] = Object.const_get(key.camelize).from_hash value end end self.new h end def self.from_json( json ) hash = ActiveSupport::JSON.decode json self.from_hash hash end # The xml has a surrounding class tag (e.g. ship-to), # but the hash has no counterpart (e.g. 'ship_to' => {} ) def self.from_xml( xml ) hash = Hash.from_xml xml self.from_hash hash[self.to_s.underscore] end
Also available on pastie.
Example usage, using the to_xml example:
xml = firm.to_xml :include => [ :account, :clients ] firm = Firm.from_xml xml
Note: this only works if the classes of the nested objects are canonically named. If any of your associations use the :class_name option, you will probably need to update this code to discover the proper class names.
I just wrote this a couple hours ago, so please consider this to be an alpha version.

3 Comments
Thanks Matt. It was nice to find that i wasn’t alone w/ the weird from_xml behavior. ‘Preciate the sample code too.
I knew I wasn’t the only one.
I’ve since generalized the code and tested it more thoroughly. The upgrade is here.
If anyone finds any bugs, send me a simple test case and I will try to fix it.
If you need to de-serialize from XML that contains an array of objects you can also use this: http://gist.github.com/179530
One Trackback
[...] post is an upgrade to the previous post about the unmarshalling of XML and JSON strings into rails objects, with arbitrarily deep object [...]