Wednesday, 1 December 2010

Rails Nokogiri 'document already has a root node'

I'm attempting to master Ruby on Rails for a personal project and I'm not ashamed to say that I'm finding the learning curve rather steep in places.

One such place is in the generation of XML code using a builder. The advice on the web seems to strongly recommend Nokogiri, so this is what I tried to use. I ensured my Gemfile was correctly updated and ran bundle install

However, two main stumbling blocks exposed my Rails ignorance: how to properly call the XML builder from within the Rails controller, and how to cope with the dreaded cryptic 'document already has a root node' error.

The first one must be a common rookie mistake. The scaffold-generated controller had this default respond_to snippet:

respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @thing }
end

It appears what this does is to ask Rails to convert @thing into an XML representation of @thing. This is not what I wanted and it took a while to realise why my XML building code in both thing.xml.erb and thing.xml.builder were being completely ignored.

Fixing it was simple enough, remove the render block so that it reads as:

respond_to do |format|
format.html # new.html.erb
format.xml
end

This will now search for the .erb and .builder files. Time now for my next ignorant mistake.

If you call Nokogiri::XML::Builder from within a .builder file, it will fail with a 'Document already has a root node' error message.

It took me a long time to work out why. I checked my code, I copied the examples on the Nokogiri tutorials, tried various configurations and just could not find the solution. Google searches on "rails3 'document already has a root node'" did not clarify the situation either, with the few hits that showed up remaining unanswered.

Well, the solution is very straightforward: it appears Nokogiri barfs in this manner when you try running in from a .builder file. Move the code to a .erb file, and it should work fine (though you'll need to wrap it all in a %lt;%= %%gt; construct).

Simple when you know how, frustrating and tiring when you don't.

Nokogiri's slogan is: XML is like violence - if it doesn’t solve your problems, you are not using enough of it.

I clearly hadn't been using enough then...

No comments:

Post a Comment