如何使用 Active Model ArraySerializer return a json "object" 而不是 json "array"?

How to return a json "object" instead of a json "array" with Active Model ArraySerializer?

使用 Active Model Serializer,是否有一种简单且集成的方法来 return a JSON "object"(然后将其转换为 javascript 对象客户端框架)而不是 JSON "array" 序列化集合时? (我引用对象和数组,因为 returned JSON 本质上是一个字符串)。

假设我有以下 ArticleSerializer:

class ArticleSerializer < ActiveModel::Serializer
  attributes :id, :body, :posted_at, :status, :teaser, :title
end

我从 ArticlesController 调用它:

class ArticlesController < ApplicationController
  def index
    @feed = Feed.new(articles: Article.all)
    render json: @feed.articles, each_serializer: ArticleSerializer
  end
end

有没有一种方法可以将选项传递给序列化程序,使其 return 类似于:

{"articles":
  {
    "1":{ 
      ...
    },
    "2":{
      ...
    }
  }
}

而不是

{"articles":
  [
    { 
      "id":"1",
      ...
    },
    {
      "id":"2"
      ...
    }
  ]
}

编辑:我想这个 post(AMS ArraySerializer 的子类)中提出的方法可能会有所帮助 (Active Model Serializer and Custom JSON Structure)

不,从语义上讲,您返回的是一组文章。哈希只是 Javascript 中的对象,因此您本质上想要一个具有 1..n 方法的对象,每个文章 returns,但这没有多大意义。

您必须编写一个自定义适配器来适应您的格式。 或者,您可以在将哈希传递给 render 之前修改哈希。 如果您不介意迭代生成的散列,您可以这样做:

ams_hash = ActiveModel::SerializableResource.new(@articles)
                                            .serializable_hash
result_hash = ams_hash['articles'].map { |article| { article['id'] => article.except(:id) } }
                                  .reduce({}, :merge)

或者,如果您希望这是默认行为,我建议切换到 Attributes 适配器(它与 Json 适配器完全相同,除了有没有文档根),并按如下方式覆盖 serializable_hash 方法:

 def format_resource(res)
   { res['id'] => res.except(:id) }
 end

 def serializable_hash(*args)
   hash = super(*args)
   if hash.is_a?(Array)
     hash.map(&:format_resource).reduce({}, :merge)
   else
     format_resource(hash)
   end
 end