问题
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