DEV Community

RobL
RobL

Posted on • Originally published at robl.me

JBuilder Arrays and non-collections

JBuilder may not be the most efficient way to present an API but for simple cases it works pretty well. Our JSON-API standardized API could return the current authenticated user like so.

show.json.jbuilder

json.data do
  json.id current_user.id
  json.type 'users'
  json.attributes do
    json.(current_user, :uuid, :email, :full_name)
  end
end
Enter fullscreen mode Exit fullscreen mode

GET /api/v1/me

{
  "data": {
    "id": "1a2b3c4d000001",
    "type": "users",
    "attributes": {
      "uuid": "aaaaaaaabbbbbbbbccccccccc",
      "email": "rob.lacey@buttonmoon.co.uk",
      "full_name": "Mr Rob Lacey"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Ideally I want to now add an included block so that can included related objects such as Tenant. Something like

{
  "data": {
    "id": "1a2b3c4d000001",
    "type": "users",
    "attributes": {
      "uuid": "aaaaaaaabbbbbbbbccccccccc",
      "email": "rob.lacey@buttonmoon.co.uk",
      "full_name": "Mr Rob Lacey"
    },
    "included": [
      {
        "id": "1",
        "type": "tenants",
        "attributes": {
          "name": "superadmin"
        }
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

All of the JBuilder examples talk in terms of Arrays of objects being built from a collection. Most of the time they probably are.

json.array! @comments do |comment|
  next if comment.marked_as_spam_by?(current_user)

  json.body comment.body
  json.author do
    json.first_name comment.author.first_name
    json.last_name comment.author.last_name
  end
end

# Or
json.array! @people, :id, :name
Enter fullscreen mode Exit fullscreen mode

But not always. If we want to add an array that is made up or arbitrary builder blocks, you find yourself thinking in terms of doing.

json.included do
  json.merge! do
    json.id current_user.tenant_id
    json.type 'tenants'
    json.attributes do
      json.(current_user.tenant, :name)
    end
  end
end
json.included [
  json.data do
    json.id current_user.tenant_id
    json.type 'tenants'
    json.attributes do
      json.(current_user.tenant, :name)
    end
  end
end
]
Enter fullscreen mode Exit fullscreen mode

Neither of which work, turns out the way to do it is using the undocumented child! method.

json.data do
  json.id current_user.id
  json.type 'users'
  json.attributes do
    json.(current_user, :uuid, :email, :full_name)
  end

  json.included do
    json.child! do
      json.id current_user.tenant_id
      json.type 'tenants'
      json.attributes do
        json.(current_user.tenant, :name)
      end
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Think I’ll do a pull request for the README as this took me a while to work out. https://github.com/rails/jbuilder/pull/507

Top comments (0)