如何在使用 group_by 时使用 ActiveModelSerializer?

5

我正在Rails中使用active_model_serializer。我有两个序列化程序:TodoSerializerProjectSerializer

class TodoSerializer < ActiveModel::Serializer
  attributes :id, :project, :note
  has_one :project
end

class ProjectSerializer < ActiveModel::Serializer
  attributes :id, :name
  has_many :todos
end

当我调用时:
render json: @todos

一切工作得很好,我获得了期望的输出。然而,当我调用以下代码时:

render json: @todos.group_by(&:project_id)

它返回另一个JSON调用,但不起作用。

我也尝试过:

render json: @todos.group_by(&:project_id), serializer: TodoSerializer

如果我这样做,就会出现错误。

> undefined method `id' for #<Hash:0x007fbec2241660>

你说的是什么意思它会回到另一个JSON调用,但它不起作用。 - MilesStanfield
@MilesStanfield 我的意思是它不遵循序列化规则,而且无论是否存在序列化程序,它都会给出相同的输出。 - Johnston
3
你可以使用以下代码:render json: @todos.map { |todo| TodoSerializer.new(todo).as_json }.group_by { |todo| todo['project_id'] } - Kuldeep
1个回答

5

我刚遇到了类似的问题,并找到了一个解决方案,我觉得还不错:

class GroupedTodoSerializer < ActiveModel::Serializer

  def attributes
    { project_id => serialized_todos }
  end

  private 

  def serialized_todos
    todos.map{ |todo| serialize_todo(todo) }
  end

  def serialize_todo todo
    TodoSerializer.new(todo, root:false) # you can opt out on the root option
  end

  def todos
    object.last
  end

  def project_id
    object.first
  end
end

然后在控制器中执行:
render json: @todos.group_by(&:project_id).to_a, each_serializer: GroupedTodoSerializer

这个技巧的作用是,你将从group_by返回的Hash转换为数组,然后为该数组编写一个自定义的each_serializer。由于这种方法很常见,所以我在这里发布了更普遍的解决方案: https://makandracards.com/bitcrowd/38771-group_by-with-activemodel-serializers 更新:我刚发现它产生了一个略微偏离JSON字符串的问题,因为它从to_a中多了一个数组括号。我已经更新了makandracard,但这个解决方案可能会在下一个版本的gem中失效。但是0.10.0仍处于RC状态,没有向后兼容性。
class GroupedSomeModelSerializer < ActiveModel::Serializer

  # method override
  def serializable_hash
    @object.map do |some_group_key, some_models|
      [ some_group_key , serialized_some_models(some_models) ]
    end.to_h
  end

  private

    def serialized_some_models some_models
      some_models.map{ |some_model| SomeModelSerializer.new(some_model, root: false) }
    end

end

然后在控制器中:

@some_models = SomeModel.all.group_by(&:some_group_key)
render json: @some_models, serializer: GroupedSomeModelSerializer

顺便提一下,对于较新版本的AMS,您需要覆盖serializable_object(options={})才能使其正常工作。 - smallbutton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接