Question

Is it possible to override how #to_xml renders a method result if it's an Array?

Given #numbers is not a field but a method And @object.numbers #=> [0,1,2,3,4,5]

currently it does:

@object.to_xml(:methods => :numbers)
=> "<object><numbers>012345</numbers></object>"

is it possible to override this behavior so it returns:

@object.to_xml(:methods => :numbers)
=> "<object>
      <numbers>
        <number>0</number>
        <number>1</number>
        <number>2</number>
        <number>3</number>
        <number>4</number>
        <number>5</number>
      </numbers>
    </object>"

(formatted so it's easily read)

Thanks in advance for your suggestions!

Was it helpful?

Solution

You have two options:

  1. Upgrade to Rails 3. It already has the desired output.

    gem "activemodel", '~> 3.2.12'
    require "active_model"
    
    # This could be an Active Record model
    class Result
      include ActiveModel::Serializers::Xml
    
      def numbers
        (0..5).to_a
      end
    
      def attributes
        {}
      end
    end
    
    result = Result.new
    puts result.to_xml(:methods => :numbers)
    

    Outputs:

    <?xml version="1.0" encoding="UTF-8"?>
    <result>
      <numbers type="array">
        <number type="integer">0</number>
        <number type="integer">1</number>
        <number type="integer">2</number>
        <number type="integer">3</number>
        <number type="integer">4</number>
        <number type="integer">5</number>
      </numbers>
    </result>
    
  2. Use XML Builder where you are in full control of the output. You will have to specify all attributes manually.

    # app/views/results/show.xml.builder
    xml.instruct!
    xml.result {
      xml.numbers {
        result.numbers.each do |n|
          xml.number n
        end
      }
    }
    

    Outputs:

    <?xml version="1.0" encoding="UTF-8"?>
    <result>
      <numbers>
        <number>0</number>
        <number>1</number>
        <number>2</number>
        <number>3</number>
        <number>4</number>
        <number>5</number>
      </numbers>
    </result>
    

OTHER TIPS

You can use the :procs option to add a custom rendering for your method inside the model:

def to_xml(options={})
  numbers_proc = Proc.new do |options|
    xml = options[:builder]
    xml.numbers do
      numbers.each do |n|
        xml.number n
      end
    end
  end
  super options.merge(:procs => numbers_proc)
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top