Understanding Rails model serializers
Tweet Follow @hazula
Since this post is long, I’ve divided it into sections:
- How Serializers Work
- How Renderers Work
- Example code changing the renderer
- Example code changing the serializer
- Proposal
How serializers work:
Right now (Rails 4.2), that interface has two private-looking methods
:_render_with_renderer_json
or :_render_option_json
(for example usage, see ActionController:: Serialization)
Such that creating a serializer is complicated and non-obvious:
which is really hard to find in the source code, since it calls "_render_with_renderer_#{key}"
where key
is json
.
that is, it calls "send(:render_with_renderer_json, @model, options)"
which is not greppable in the code base
(@model
is the argument to json: in the controller, for example render json: @model
)
How renderers work:
How does the renderer fit into this? Well, when a controller has
the @model
is passed to the JSON Renderer (see ActionController::Renderers default)
which basically calls json = @model.to_json(options)
Example code changing the renderer:
If, for example, I wanted to change how the JSON was rendered, to pretty print it,
I would just redefine the :json
renderer as below
Example code changing the serializer:
But, to change how the @model
is serialized, a library such as what ActiveModelSerializers
overrides :_render_option_json
and :_render_with_renderer_json
to basically change @model = ModelSerializer.new(@model)
so that the renderer is calling :to_json/:as_json
on the serializer
I think this could be way better:
PROPOSAL:
1) Renderer
could have a method :serializer_for
that can by default returns its argument, but can be overridden in the controller
example controller code:
or
2) have a serializer registry (like renderers and mime-types have), that may be called in a method just as in #1
Benefits:
- Simple, clear, extendable interface for model serialization
- Less meta-programming
- I wouldn’t have needed to spend hours in the debugger and rails source code trying
to find out the path from
render json: @model
to_render_with_renderer_json(@model, options)
Thanks for reading this far! Let me know what you think!
Originally posted as an RFC to rubyonrails-core mailing list.
Follow any discussion of the RFC there.
blog comments powered by Disqus