How to use ActiveModelSerializer with group_by?

ⅰ亾dé卋堺 提交于 2019-12-10 16:34:31

问题


I am using active_model_serializer in rails. I have two serializers: TodoSerializer and ProjectSerializer

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

and

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

When I call

render json: @todos

Everything works great and I get the output I expect. However when I call:

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

It reverts back to another JSON call and it doesn't work.

I also tried:

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

If I do that I get the error

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

回答1:


I just had a similar problem and worked out a solution that I found quite ok to live with:

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

And then in the controller you do

render json: @todos.group_by(&:project_id).to_a, each_serializer: GroupedTodoSerializer

The trick works, since you change the Hash that is returned from the group_by to an array and then write a custom each_serializer for that array.

I published a more general version of the solution here: https://makandracards.com/bitcrowd/38771-group_by-with-activemodel-serializers

UPDATE:

I just found out that it produces a slightly off JSON string, since it has an array bracket too much from the to_a.

I updated the makandracard, but this solution will probably break in the next release of the gem. But 0.10.0 is still in RC state and has no backward compatibility.

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

Then in the controller:

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


来源:https://stackoverflow.com/questions/35616592/how-to-use-activemodelserializer-with-group-by

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!