Search code examples
ruby-on-railsjsonrabl

How to create custom "containing" JSON in RABL?


I'm writing an API with two types of endpoints: single and aggregate. I have RABL views for the single endpoints, below:

# cat_view.json.rabl
object @cat
attributes :name

# dog_view.json.rabl
object @dog
attributes :name

These work as expected, however I'm struggling with the aggregate RABL view. The JSON structure I want is:

{
  'cats': {
    'details': [{'name': 'Mittens'},
                {'name': 'Mr. Wiskers'},
                {'name': 'Crookshanks'}],
    'count' : 3
  },
  'dogs': {
    'details': [{'name': 'Rover'},
                {'name': 'Fido'}],
    'count' : 2
  }
}

My current aggregate RABL view is:

# animals.json.rabl
child @cats do
  collection @cats, :object_root => false
  extends "cat_view"
end
node(:cat_count) { @cats.count }

child @dogs do
  collection @dogs, :object_root => false
  extends "dog_view"
end
node(:dog_count) { @dogs.count }

Which results in this JSON:

    {'cats': [{'name': Mittens'},
              {'name': Mr. Wiskers'},
              {'name': Crookshanks'}],
    'cat_count': 3,
    'dogs': [{'name': 'Rover'},
             {'name': 'Fido'}],
    'dog_count': 2}

My question:

How should my animals.json.rabl look in order to get the JSON structure described above?


Solution

  • In order to add the details key, name your existing child @cats block details:

     child @cats => :details do
       collection @cats, :object_root => false
       extends "cat_view"
       node(:count) { @cats.count }
     end
    

    For the nesting part of your question, you can do this by creating a new wrapping child block:

    # animals.json.rabl
    child :cats do
     child @cats => :details do
       collection @cats, :object_root => false
       extends "cat_view"
       node(:count) { @cats.count }
     end
    end
    
    child :dogs do
     child @dogs => :details do
       collection @dogs, :object_root => false
       extends "dog_view"
       node(:count) { @dogs.count }
     end
    end