ActiveModelSerializer::Namespaces
Compatibility note
This gem is designed for Active Model Serializers 0.8.x only. It won't be updated for 0.9 neither for 0.10 due to fundamental architecture changes in Active Model Serializers.
When is it useful?
Short answer: when you need more than one way to serialize your models and you want to organize that in namespaces.
One example is that your application is serving a versioned API. You want to freeze the old APIs and actively develop upcoming version.
Another example is that your application is utilizing few 3rd-party services which expect JSONs as input, so you need to convert your models somehow, preferably avoiding mixing different representations for various integrations.
In all these cases the most natural approach is to define a separate set of
serializers for every API version or integration. But then you discover that
you need to pass serializer name every time you use it. Even #has_many
declarations in serializers require that. And what will you do to serialize
a collection of objects of different classes?
With ActiveModelSerializer-Namespaces, you can nest your serializers in modules with no pain. Just pass namespace of your choice and it will be used throughout complex models and collections. What's more, you don't need to type it in every controller action, it's enough to specify it as default in a base controller or mixin module once for the whole API version.
Creating new API version is as easy as copying code to new location.
How do I use it?
Given:
class Article < ActiveRecord::Base
end
module V1
class ArticleSerializer < ActiveModel::Serializer
end
end
Either specify namespace directly at render
call:
def some_action
render json: article, serialization_namespace: Ver1
end
Or set it as a default option in controller:
def some_action
render json: article
end
def default_serializer_options
{serialization_namespace: Ver1}
end
See spec/features_spec.rb
for more detailed examples.
How does it work (caveats)?
The trick is to delay inferring serializer class until #new
is called and
the options hash is available.
To achieve that, ::active_model_serializer
is defined for all models which
returns a finder proxy object instead of serializer class. The finder instance
responds to #new
call as would the real class, but it performs a lookup for
correct serializer class before instantiating a serializer object. This way
it's fully transparent for Active Model Serializer internals.
As a consequence, overriding #active_model_serializer
or ::active_model_serializer
disables this gem for given model.
Why is it a separate gem?
I did want to solve one of the biggest drawbacks of Active Model Serializers 0.8. I didn't want to introduce backwards-incompatible changes into it's API.
Contributing
Fork it, improve it then create a pull request. You know the drill.
See also
- Active Model Serializers issue tracker, particularly #144, but also: #562, #671, #735 and more.
- ActiveModel::VersionSerializer — different approach to solve the problem