Search code examples
ruby-on-railsactiveresource

How do I change a XML tag when I do update_attributes to a RESTful API?


I've got a non-Rails RESTful API that I can easily connect to with ActiveResource, and GETting the data when I do a find simply works. But, updating the data isn't as straight forward. I think it's because the API wants the XML body wrapped in this non-standard XML tag of <platform_user> rather than <hash> which is what the GET request is wrapped in.

How would I modify the basic XML template when doing an update_attributes so that it can contain the <platform_user>?

And generally, I haven't been able to find much guidance on using ActiveResource in this way. Any books or web sites out there that you can point me to?

Thanks much.


Solution

  • I'd actually be quite surprised if your problem will be resolved by simply renaming or wrapping inside a parent node and I'm assuming you are going to run into a more issues with your service as you get closer to a solution. I've (unfortunately) been in this boat before so I'm writing what I've learned.

    In general, I've found it somewhat difficult to deal with services through ActiveResource when the service expects some complex or otherwise ugly XML. My solutions in these cases inevitably end up overriding the object's to_xml method since the create (POST) or update (PUT) should internally call the object's to_xml to serialize your data into XML. Said methods could either utilize ruby's xml builder or you could also use a 'here document' for even more tricky stuff. I think the bottom line is, you have to know exactly what your service is expecting and build that structure to send off to the service.

    For example using 'here document' to force an unfriendly xml structure:

    class User << ActiveResource::Base
    
      def to_xml
        xml =<<-EOS
          <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
          <platform_user>
            <user xsi:type="userData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
              <userId>#{self.id}</userId>
              <userName>#{self.name}</userName>
              <addresses>
                <address>
                  <address1>#{self.address1}</address1>
                  <addressZip>#{self.zip}</addressZip>
                </address>
              </addresses>
            </user>
          </platform_user>
        EOS
        xml.gsub(/\n|\t|\r/,"").strip #clean it up.
      end
    end
    

    You could also use XML Builder it it works for your structure, for example:

    def to_xml
      xml = Builder::XmlMarkup.new()
        xml.instruct! :xml, :version => "1.0", :encoding => "UTF-8", :standalone=>"yes"
        xml.platform_user do
            xml.user do
              xml.userId self.id
              ...
            end
        end
    end 
    

    Good luck.