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

Posted

技术标签:

【中文标题】在 ActiveModel::Serializer 中序列化错误哈希【英文标题】:Serializing the errors hash in ActiveModel::Serializer 【发布时间】:2014-10-17 22:01:47 【问题描述】:

我正在使用 ActiveModel::Serializer 为我的 API 自定义 JSON 响应。这在大多数情况下都可以正常工作,除非它无法成功保存模型。

例如,

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

    respond_with book, location: nil
  end
end

据我了解,respond_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】:

我在this blog post 上找到了这个答案...开始是这样...

Rails 中错误状态的默认序列化可能不是什么 你想要你的应用程序。在这种情况下,值得知道如何 根据您的需要编写自定义序列化格式。就我而言,我是 试图匹配JSON API format for errors。这里有潜力 实施……

验证错误示例

默认情况下,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的实际帖子。

【讨论】:

【参考方案2】:

我认为这种情况下的问题在于,对于 failed 状态,您不会像 created 状态那样使用对象调用 render

您可以在调用render 时使用自定义序列化程序,对于这种情况,您可能可以使用类似

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

试一试,让我们知道结果:)

【讨论】:

【参考方案3】:

ErrorsSerializer 不起作用,因为响应者如何为错误创建 json 响应:

def json_resource_errors
   errors: resource.errors 
end

(rails https://github.com/rails/rails/blob/4-1-stable/actionpack/lib/action_controller/metal/responder.rb#L290 对于较新的 rails,响应者已提取到 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

然后您的序列化程序将适用于资源错误。

【讨论】:

【参考方案4】:

resource.errors 的类名是ActiveModel::Errors,所以你必须将你的类定义为 ActiveModel::ErrorsSerializer.

参考:source code

【讨论】:

是的,我就是这么做的。正如我在问题中所说 - 当我执行 ActiveModel::Serializer.serializer_for 时,它会找到我的序列化程序,但它没有被使用。 你能用你的 ErrorSerializer 代码更新问题吗?

以上是关于在 ActiveModel::Serializer 中序列化错误哈希的主要内容,如果未能解决你的问题,请参考以下文章

NOIP 2015 & SDOI 2016 Round1 & CTSC 2016 & SDOI2016 Round2游记

秋的潇洒在啥?在啥在啥?

上传的数据在云端的怎么查看,保存在啥位置?

在 React 应用程序中在哪里转换数据 - 在 Express 中还是在前端使用 React?

存储在 plist 中的数据在模拟器中有效,但在设备中无效

如何在保存在 Mongoose (ExpressJS) 之前在模型中格式化数据