How to create a json response with nested json objects?

Viewed 80

I'm creating an api in ruby on rails, I have a couple tables events, artists, and countries, events has artist_id which is a foreign key to the id field in artists. Events also has country_id, which is a foreign key to country id field. When a user asks my api for /events/artist/:artist_id, I want to return json results in the form of

[
{
    "id":1,
    "type":"festival",
    "artist":{
      "id":1,
      "name":"doesnt matter"
    },
    "country":{
      "id":1,
      "name":"cambodia"
    }
]

I'm unsure however how to include nested objects in my json response, would I do multiple queries and some how inject them into my json response? I am sure there are better ways to set up my database for this as well and I'm open to suggestions but an event can only have one artist and be in one country, though countries can have multiple events. The core of my issue is not the database though, I cant find any information how to nest queries in my response.(Which is I think what I need to do) ruby on rails - 6.0.2, ruby 2.7.1

1 Answers

You can use as_json method on your events.

It's fully customizable:

@artist = Artist.find(params[:artist_id])

@artist.events.as_json(
  only: [:id, :type],
  include: [
    artist: {only: [:id, :name]},
    country: {only: [:id, :name]}
  ]
)

However, this would generate one query for Event.all plus two queries for each event. To preload all artists and countries and do only 3 queries you can do:

@artist.events.includes([:artist, :country]).as_json(
  only: [:id, :type],
  include: [
    artist: {only: [:id, :name]},
    country: {only: [:id, :name]}
  ]
)

In addition to that, you shouldn't return artist json for each event if the artist is always the same. (since you searched for events associated to the same artist). You would get useless data duplication. You may try to format your data the other way:

@artist.as_json(
  only: [:id, :name],
  include: [
    events: {
      only: [:id, :name],
      include: {
        country: {only: [:id, :name]}
      }
    }
  ]
)
Related