【问题标题】:Serializing the errors hash in ActiveModel::Serializer在 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 响应?

【问题讨论】:

    标签: ruby-on-rails json serialization ruby-on-rails-4 active-model-serializers


    【解决方案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 代码更新问题吗?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-02-01
          • 2013-07-03
          • 1970-01-01
          • 1970-01-01
          • 2018-10-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多