Сериализаторы активной модели: добавление дополнительной информации вне корня в ArraySerializer

Скажем, у меня есть модель User и сериализатор UserSerializer < ActiveModel::Serializer, и контроллер выглядит следующим образом:

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

Теперь, если я нахожусь в /users, я получу ответ JSON, который выглядит так:

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

Но что, если я хочу включить некоторую дополнительную информацию в ответ JSON, не относящийся ни к одному конкретному пользователю? Например:.

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

Этот пример надуман, но это хорошее приближение к тому, чего я хочу достичь. Возможно ли это с помощью активных сериализаторов моделей? (Возможно, путем подкласса ActiveModel::ArraySerializer? Я не мог понять это). Как добавить дополнительные корневые элементы?

Ответ 1

Сработала с помощью render:

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

Проблема в том, что это не вызов UserSerializer, он просто вызывает .as_json для каждого отдельного пользовательского объекта и пропускает Сериализатор. Поэтому я должен был сделать это явно:

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

Не самое элегантное решение, но оно работает.

Ответ 2

Вы можете передать их в качестве второго аргумента для response_with

def index
 respond_with User.all, meta: {time: "2014-01-06 16:52 GMT",url: "http://www.example.com", noOfUsers: 2}
end

В версии 0.9.3 в наборе инициализаций ActiveModel::Serializer.root = true:

ActiveSupport.on_load(:active_model_serializers) do
  # Disable for all serializers (except ArraySerializer)
  ActiveModel::Serializer.root = true
end

В контроллере

render json: @user,  meta: { total: 10 }

Ответ 3

Просто простой взлом, если вы не хотите изменять сериализатор или рендеринг:

data = serializer.new(object, root: false)
# cannot modify data here since it is a serializer class
data = data.as_json
# do whatever to data as a Hash and pass the result for render
data[:extra] = 'extra stuff'
render json: data

Ответ 4

Мне удалось заставить это работать для моего использования, просто добавив следующее в мой контроллер. Больше ничего не нужно с AMS 0.10.

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