Сериализация хэша ошибок в ActiveModel:: Сериализатор

Я использую ActiveModel:: Serializer для настройки ответов JSON для моего API. Это прекрасно работает в большинстве случаев, за исключением случаев, когда он не смог успешно сохранить модель.

Например,

def create
  def create
    book = Book.new(book_params)
    book.save

    respond_with book, location: nil
  end
end

Как я понимаю, действие response_with будет в основном выполнять код, который выглядит примерно так (для генерации ответа).

  if resource.errors.any?
    render json: {:status => 'failed', :errors => resource.errors}
  else
    render json: {:status => 'created', :object => resource}
  end

Это соответствует тому, что я вижу - если моя модель не удается успешно сохранить, я вижу хеш-ошибки в качестве ответа. Тем не менее, я не могу понять, как я указываю сериализатор для хэш-ошибок.

Я попытался определить ErrorsSerializer, и если я запустил

ActiveModel::Serializer.serializer_for(book.errors)

в консоли, похоже, находит мой сериализатор, но он не используется. Как настроить ответ JSON в этом сценарии?

Ответ 1

Я считаю, что проблема в этом случае заключается в том, что для статуса failed вы не вызываете render с объектом, как для статуса created.

Вы можете использовать пользовательский Сериализатор при вызове render, для этого случая вы, вероятно, можете использовать что-то вроде

if resource.errors.any?
  render serializer: ErrorSerializer, json: {:status => 'failed', :errors => resource.errors}
else
  render json: {:status => 'created', :object => resource}
end

Попробуйте и сообщите нам о результатах:)

Ответ 2

ErrorsSerializer не работает из-за того, как ответчики создают ответ json для ошибок:

def json_resource_errors
  { errors: resource.errors }
end

(rails < 4.2 https://github.com/rails/rails/blob/4-1-stable/actionpack/lib/action_controller/metal/responder.rb#L290 для новых рельсов, респонденты были извлечены в https://github.com/plataformatec/responders/blob/master/lib/action_controller/responder.rb#L288)

Один из способов борьбы с этим - переопределить этот метод для респондентов. Поместите этот код в свои инициализаторы конфигурации:

# config/initializers/action_controller_responder.rb
module ActionController
  class Responder
    def json_resource_errors
      resource.errors
    end
  end
end

Затем ваш сериализатор будет работать для ошибок ресурсов.

Ответ 3

Я нашел этот ответ на этом сообщении в блоге... который начинается как таковой...

Стандартная сериализация состояний ошибок в Rails может быть не такой, как вы хотите для своего приложения. В этом случае стоит знать, как напишите собственный формат сериализации для ваших нужд. В моем случае я пытаясь сопоставить формат JSON API для ошибок. Имеет потенциал осуществление...

Пример ошибки проверки

По умолчанию Rails 4 вернет сериализацию ошибок, которая выглядит так (для книжной модели, где title всегда должен присутствовать):

{
  "title": [
    "can't be blank"
  ]
}

Создать собственный сериализатор ошибок

В /serializers/error_serializer.rb...

module ErrorSerializer

  def self.serialize(errors)
    return if errors.nil?

    json = {}
    new_hash = errors.to_hash(true).map do |k, v|
      v.map do |msg|
        { id: k, title: msg }
      end
    end.flatten
    json[:errors] = new_hash
    json
  end
end

Используйте его в своем контроллере

Теперь include ErrorSerializer в вашем контроллере, чтобы вы могли сделать что-то подобное с помощью хэша ошибок, т.е. render: json: ErrorSerializer.serialize(book.errors)

Результат

{
  "errors": [
    {
      "id": "title",
      "title": "Title can't be blank"
    }
  ]
}

Прочитайте фактическое сообщение для deets.

Ответ 4

Имя класса resource.errors ActiveModel::Errors, поэтому вы должны определить свой класс как ActiveModel::ErrorsSerializer.

Ссылка: исходный код