在 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游记