Active_model_serializers: can't specify serializer for a collection

Created on 31 May 2012  路  8Comments  路  Source: rails-api/active_model_serializers

In a controller, if I:
render json: Post.all, serializer: SpecialSerializer

it fails with the exception:
undefined method `read_attribute_for_serialization' for #ActiveRecord::Relation:0x000000030bcf18

It's trying to use the SpecialSerializer on the list of Posts, not on each post. If I pass in serializer: ArraySerializer, it asks Post what its serializer is and uses the default PostSerializer instead of the SpecialSerializer I want to specify. I don't want to define Post#active_model_serializer because everywhere else I do want to use PostSerializer, not the SpecialSerializer.

I'm not sure how this should be fixed: letting ArraySerializer take an option specifying a serializer, or _render_option_json should know how to deal with enumerables, or if there's some better approach for my controller that I'm completely missing. Ideas?

Most helpful comment

@josevalim I don't understand how this answers @ahawkins 's question.

It seems to me that we should be able to tell the render to just use a serializer "because I said so"?

All 8 comments

Do either of these options work?

  • render json: Post.all, serializer: ArraySpecialSerializer which knows it's getting an array of said objects, or...
  • Post.all.each{|p| render json: p, serializer: SpecialSerializer}

The first example... I guess? I'd have to inherit from ArraySerializer and override serializable_array, which has a decent amount of logic in it. Then I have two custom classes to do one thing, and it's going to break in weird and frustrating ways anytime ArraySerializer changes - and it doesn't look to me like it's intended to be a public API. (Not mentioned in readme, minimal docs.)

The latter option creates a double render error. Even if I change it to render json: Post.all.each { |p| SpecialSerializer.new(p) } I end up having to tell SpecialSerializer not to include a root element and then add it back at the top level myself, it feels really clunky and not right.

letting ArraySerializer take an option specifying a serializer, or _render_option_json should know how to deal with enumerables,

We need a mix of both options. Maybe we could support a :each_serializer option in the ArraySerializer that then you could pass when calling render:

render :json => @posts, :each_serializer => :my_special_serializer

Pull request please?

Here's a pull request to support the :each_serializer option as specified. I'm using it in my app successfully. Thanks for confirming that I had the right idea about how to approach this.

@thegrubbsian's pull request doesn't solve this issue, as ArraySerializer will still ask the model for its serializer.

@josevalim why not just support render :json => thing, :serializer => foo. Isn't this how it already works?

The :serializer option would change what serializes the whole collection.

@josevalim I don't understand how this answers @ahawkins 's question.

It seems to me that we should be able to tell the render to just use a serializer "because I said so"?

Was this page helpful?
0 / 5 - 0 ratings