Search code examples
ruby-on-railsrubyactivemodelactive-model-serializers

Active Model Serializers: Adding extra information outside root in ArraySerializer


Say I have a model User and a serializer UserSerializer < ActiveModel::Serializer, and a controller that looks like this:

class UsersController < ApplicationController
  respond_to :json
  def index
    respond_with User.all
  end
end

Now if I visit /users I'll get a JSON response that looks like this:

{
  "users": [
    {
      "id": 7,
      "name": "George"
    },
    {
      "id": 8,
      "name": "Dave"
    }
    .
    .
    .
  ]
}

But what if I want to include some extra information in the JSON response that isn't relevant to any one particular User? E.g.:

{
  "time": "2014-01-06 16:52 GMT",
  "url": "http://www.example.com", 
  "noOfUsers": 2,
  "users": [
    {
      "id": 7,
      "name": "George"
    },
    {
      "id": 8,
      "name": "Dave"
    }
    .
    .
    .
  ]
}

This example is contrived but it's a good approximation of what I want to achieve. Is this possible with active model serializers? (Perhaps by subclassing ActiveModel::ArraySerializer? I couldn't figure it out). How do I add extra root elements?


Solution

  • Got it working using render:

    render json: {
      "time": "2014-01-06 16:52 GMT",
      "url": "http://www.example.com", 
      "noOfUsers": 2,
      "users": @users
    }
    

    The problem is, this doesn't call UserSerializer, it just calls .as_json on each individual user object and skips the Serializer. So I had to do it explicitly:

    def index
      .
      .
      .
      render json: {
        "time": "2014-01-06 16:52 GMT",
        "url": "http://www.example.com", 
        "noOfUsers": 2,
        "users": serialized_users
      }
    end
    
    def serialized_users
      ActiveModel::ArraySerializer.new(@users).as_json
    end
    

    Not the most elegant solution but it works.