Tuesday, May 08, 2007

ActiveRecord::Base#to_xml woes

For us Railies that use namespaced models inside Ruby modules and are relying on ActiveRecord::Base#to_xml, do not fret any longer.

To reproduce the problem you just need to do something like:

users = Legacy::User.find(:all) #=> []
users.to_xml #=> <?xml version=\"1.0\" encoding=\"UTF-8\"?><legacy/users></legacy/users>

The XML produced by #to_xml is NOT valid XML for this case.

It's been a small thorn in my side for a week or so now and I've been living with it by adding the following to a file that is eventually/implicitly required by environment.rb:


# Patch for Rails #8305 that I submitted on 2007-05-09
# We'll need to keep an eye out upon next Rails Gem upgrade whether or not this
# fix has been applied to remove this or not.
require 'active_record'
require 'active_support'

class ActiveRecord::Base
alias :old_to_xml :to_xml
def to_xml(options = {}, &block)
options[:root] ||= self.class.name.tableize.singularize.gsub(/\//, ':') # for models that are namespaced in Ruby module
old_to_xml(options, &block)
end
end

module ContainerPatchMixin
def self.included(base)
base.class_eval %{
alias :old_to_xml :to_xml
}
base.send(:include, InstanceMethods)
end

module InstanceMethods
def to_xml(options = {})
contained_class = self.first.class.name
options[:root] ||= contained_class.tableize.gsub(/\//, ':') # for models that are namespaced in Ruby module
options[:children] ||= contained_class.tableize.singularize.gsub(/\//, ':') # for models that are namespaced in Ruby module
old_to_xml(options)
end
end
end

class Array
include ContainerPatchMixin
end

Now what is produced is something more along the lines of:

<?xml version=\"1.0\" encoding=\"UTF-8\"?><legacy:users></legacy:users>

Which is valid XML.

Today I finally reported this edge case defect on dev.rubyonrails.org (#8305) as I hadn't seen anyone else report it yet.

Thankfully this is Ruby and this is all possible while the Rails Core team determine if my not so elegant fix is worthy to be in the next Rails version or not.

0 comments: