Diogo Wernik
Diogo Wernik

Reputation: 638

Custom json on rails 5 api only, using to_json

I am working on a rails 5 api only. I can get all the data that i want, but i would like to customize the output.I tried some solutions, but couldn't find it yet.

This is my portfolio controller:

  def show
    render json: @portfolio.to_json(
      :only => [:title],
      :include => {
        :cryptos => {
          :only => [],  
          :include => [
            {:radarcrypto => { :only => [:ticker, :price] }},
          ]},
        }
      )
  end

this is the output

{
  title: "Portfolio 1",
  cryptos: [
   {
     radarcrypto: {
         ticker: "BTC",
         price: "190919.85",
    }
 },
  {
     radarcrypto: {
        ticker: "ETH",
        price: "12220.18",
  }
},
],
}

But i would like something like that:

{
  title: "Portfolio 1",
  cryptos:
    {
     ticker: "BTC",
     price: "190919.85",
    },
    {
     ticker: "ETH",
     price: "12220.18",
    },
}

this are my models


class Portfolio < ApplicationRecord
    has_many :cryptos
end

class Radarcrypto < ApplicationRecord
    has_many :cryptos
end

class Crypto < ApplicationRecord
    belongs_to :portfolio
    belongs_to :radarcrypto
end

I already tried to use without success:

class Radarcrypto < ApplicationRecord
    ApplicationRecord.include_root_in_json = false
end

I don't know if there is a better solution to this customization, if would be better to use the views, json.jbuilder for example. thanks.

Upvotes: 1

Views: 74

Answers (1)

H. Almidan
H. Almidan

Reputation: 518

It's not possible to include a collection of objects as a value to a key without wrapping them in an array in JSON. (source (W3Schools))

It is possible, on the other hand, to have a collection of objects, but each one would have to have its own unique key. So the response could be shaped as such:

{
  title: "Portfolio 1",
  cryptos: {
    BTC: {
     ticker: "BTC",
     price: "190919.85",
    },
    ETH: {
     ticker: "ETH",
     price: "12220.18",
    },
}

(A different key is going to have to be used if more than one radarcrypto can have the same ticker)

I'm not sure how that would be achieved using the to_json options (e.g. include and only). You could probably do it manually by doing:

def show
  portfolio = {};
  portfolio['title'] = @portfolio.title
  portfolio['cryptos'] = {}
  @portfolio.cryptos.each do |crypto|
    radarcrypto = crypto.radarcrypto
    portfolio['cryptos']["#{radarcrypto.ticker}"] = {
      'ticker': radarcrypto.ticker,
      'price': radarcrypto.price
    }
  end

  render json: portfolio.to_json
end

Side note

A gem such as Jbuilder may be a good candidate if nested shaping of JSON responses is done in multiple controllers.

Upvotes: 1

Related Questions