Harish Shetty
Harish Shetty

Reputation: 64363

XML Serialization issue in ActiveRecord serializable attributes

I have a serialized field called options(of type Hash) in my User model. The options field behaves like a Hash most of the time. When I convert the user object to XML, the 'options' field is serialized as a YAML type instead of Hash.

I am sending the result to a Flash client via REST. This behaviour is causing problems at the client side. Is there a way to address this?

class User < ActiveRecord::Base
  serialize :options, Hash
end

u = User.first
u.options[:theme] =  "Foo"
u.save

p u.options # prints the Hash

u.to_xml    # options is serialized as a yaml type: 
            # <options type=\"yaml\">--- \n:theme: Foo\n</options>

EDIT:

I am working around this issue by passing a block to to_xml.(similar to the solution suggested by molf)

u.to_xml(:except => [:options])  do |xml|
  u.options.to_xml(:builder => xml, :skip_instruct => true, :root => 'options')
end

I wondering if there is a better way.

Upvotes: 2

Views: 1095

Answers (1)

molf
molf

Reputation: 74985

Serialisation is done with YAML in the database. What they don't tell you is that it is also passed as YAML to the XML serializer. The last argument to serialize indicates that the objects you assign to options should be of type Hash.

One solution to your problem is to override to_xml with your own implementation. It's relatively easy to borrow the original xml builder object and pass it to to_xml of your options hash. Something like this should work:

class User < ActiveRecord::Base
  serialize :options, Hash

  def to_xml(*args)
    super do |xml|
      # Hash#to_xml is unaware that the builder is in the middle of building
      # XML output, so we tell it to skip the <?xml...?> instruction. We also
      # tell it to use <options> as its root element name rather than <hash>.
      options.to_xml(:builder => xml, :skip_instruct => true, :root => "options")
    end
  end

  # ...
end

Upvotes: 2

Related Questions