Bohn
Bohn

Reputation: 26919

Customizing output of JSON

In the controller I have a respond_with like this:

respond_with(@layer1 , @layer2)

The JSON output I need is like this:

{
   "LayerOne": [
      {
         "name": "haha",
         "number":"44"
      }, // more .... 
   ],
  "LayerTwo": [
     {
        "name": "James Bond",
        "score": 20
     } // , ....
  ]
}

So to get the first section I write the serializer like this:

class Layer1Serializer < ActiveModel::Serializer

  attributes :number, :name

  def name
    object.person.name
  end

end

And I change the controller to be like this, so I can pass a ROOT so it shows in the JSON as "LayerOne"

respond_with(@Layer1, root: 'LayerOne')

but remember at the beginning I had two things to pass to controller, so now I can't figure our how to do this for the second section of JSON that says "Layer2"

Upvotes: 4

Views: 2466

Answers (4)

rbinsztock
rbinsztock

Reputation: 3195

create a new hash and pass your array values into it.

respond_with({:LayerOne => @layer1.as_json(:only => [:name, :percentage]), :LayerTwo => @layer2.as_json(:only => [:name, :off_target_by])})

i got this json :

{
    "LayerOne": [
        {
            "name": "layer1",
            "percentage": "10.11"
        },
        {
            "name": "layer 1 bis",
            "percentage": "1212.0"
        }
    ],
    "LayerTwo": [
        {
            "name": "layer 2",
            "off_target_by": 2
        },
        {
            "name": "layer 2 bis",
            "off_target_by": 9
        }
    ]
}

hope it helps :)

EDIT 2 :

You can create an array serializer to pass your variables :

class LayerArraySerializer < ActiveModel::ArraySerializer
  self.root = false
end

and in your view :

respond_with({:LayerOne => @layer1 , :LayerTwo => @layer2}, :serializer => LayerArraySerializer)

json print :

[
    [
        "LayerOne",
        [
            {
                "percentage": "10.11",
                "name": "layer1"
            },
            {
                "percentage": "1212.0",
                "name": "layer 1 bis"
            }
        ]
    ],
    [
        "LayerTwo",
        [
            {
                "off_target_by": 2,
                "name": "layer 2"
            },
            {
                "off_target_by": 9,
                "name": "layer 2 bis"
            }
        ]
    ]
]

Upvotes: 1

moonfly
moonfly

Reputation: 1820

You can create the following intermediate class:

class BothLayers
  include ActiveModel
  def initialize(layer1,layer2)
    @layer1 = layer1
    @layer2 = layer2
  end
  attr_accessor :layer1, :layer2
end

and the following serializer:

class BothLayersSerializer < ActiveModel::Serializer
  root false
  has_many :layer1, key: "LayerOne"
  has_many :layer2, key: "LayerTwo"
end      

Then in your controller:

    both_layers = BothLayers.new(@layer1,@layer2)
    respond_with( both_layers, serializer: BothLayersSerializer )

Upvotes: 6

Chris Aitchison
Chris Aitchison

Reputation: 4654

Using the JBuilder DSL is an excellent way to solve your problem.

https://github.com/rails/jbuilder

The JSON response you want is implemented as a view, giving you complete control over how it renders.

Upvotes: 1

Benjamin Bouchet
Benjamin Bouchet

Reputation: 13181

Railcasts has an excellent video+text tutorial on AR Serializer, I'm sure you'll find your answer there

http://railscasts.com/episodes/409-active-model-serializers

Upvotes: 0

Related Questions