简体   繁体   English

在ActiveModel :: Serializer中序列化错误哈希

[英]Serializing the errors hash in ActiveModel::Serializer

I'm using ActiveModel::Serializer to customize the JSON responses for my API. 我正在使用ActiveModel :: Serializer来自定义我的API的JSON响应。 This works fine in most cases, except when it fails to save a model successfully. 这在大多数情况下都可以正常工作,除非它无法成功保存模型。

For example, 例如,

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

    respond_with book, location: nil
  end
end

As I understand it, the respond_with action will basically execute code that looks something like this (in order to generate the response). 据我了解,respond_with动作基本上会执行看起来像这样的代码(为了生成响应)。

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

This does match up with what I'm seeing - if my model fails to save successfully I see the errors hash as the response. 这与我所看到的相符 - 如果我的模型无法成功保存,我会将错误哈希视为响应。 However, I can't figure out how I specify a serializer for the errors hash. 但是,我无法弄清楚如何为错误哈希指定序列化程序。

I tried defining an ErrorsSerializer and if I run 我尝试定义一个ErrorsSerializer,如果我运行

ActiveModel::Serializer.serializer_for(book.errors)

in the console it seems to find my serializer, but it doesn't get used. 在控制台中,它似乎找到了我的序列化程序,但它没有得到使用。 How do I customize the JSON response in this scenario? 如何在此方案中自定义JSON响应?

I found this answer on this blog post ... which starts as such ... 我在这篇博文中找到了这个答案......就这样开始......

The default serialization of error states in Rails might not be what you want for your app. Rails中错误状态的默认序列化可能不是您想要的应用程序。 In that case, it'd be worth knowing how to write a custom serialization format for your needs. 在这种情况下,了解如何根据需要编写自定义序列化格式是值得的。 In my case, I am trying to match the JSON API format for errors . 在我的情况下,我试图匹配JSON API格式的错误 Here's a potential implementation… 这是一个潜在的实施......

Example validation error 示例验证错误

By default, Rails 4 will return an error serialization that looks like this (for a book model where title should always be present): 默认情况下,Rails 4将返回一个类似于此的错误序列化(对于应始终存在title的书籍模型):

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

Create a custom error serializer 创建自定义错误序列化程序

In /serializers/error_serializer.rb ... /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

Use it in your controller 在控制器中使用它

Now include ErrorSerializer in your controller so that you can do something like this using the errors hash ie render: json: ErrorSerializer.serialize(book.errors) 现在在控制器中include ErrorSerializer ,这样你就可以使用错误哈希来做这样的事情,即render: json: ErrorSerializer.serialize(book.errors)

Result 结果

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

Read the actual post for the deets . 阅读deets的实际帖子。

I believe that the problem in this case is that for the failed status you won't call render with an object, like for created status. 我相信在这种情况下的问题是,对于failed状态,您不会使用对象调用render ,例如created状态。

You can use a custom Serializer when calling render , for this case you can probably use something like 您可以在调用render时使用自定义Serializer,对于这种情况,您可以使用类似的东西

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

Give it a try and keep us informed of the result :) 试一试,告诉我们结果:)

The ErrorsSerializer doesn't work because of how responders create json response for errors: 由于响应者如何为错误创建json响应, ErrorsSerializer不起作用:

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 for newer rails, responders have been extracted to https://github.com/plataformatec/responders/blob/master/lib/action_controller/responder.rb#L288 ) (对于较新的rails,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

one way of dealing with this is to override this method for responders. 处理此问题的一种方法是为响应者覆盖此方法。 Put this code in your config initializers: 将此代码放在配置初始值设定项中:

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

Then your serializer will work for resource errors. 然后您的序列化程序将解决资源错误。

The class name of resource.errors is ActiveModel::Errors so you have to define you class as ActiveModel::ErrorsSerializer . resource.errors的类名是ActiveModel::Errors因此您必须将类定义为ActiveModel::ErrorsSerializer

Ref: source code 参考: 源代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM