TIL about Ecto schema @derive

TL;DR;

You can use @derive to choose what attributes from your model you want to serialize via Poison.encode instead of adding custom code to clean your models:

Not TL;DR; version

Today I learned about @derive, and boy, is it useful when using it to render the JSON representation of a Ecto.Schema via Poison! We’ve all been there, we try to output the JSON of a Schema and there we have the cannot encode association :some_model from MyApp.MyModel to JSON because the association was not loaded Error or the {:error, {:invalid, {nil, “my_models”}}} message. Depending on the use case, you either need to preload your dependencies or clean up the structure.

To provide some context, when serializing my models, before dispatching them via the Phoenix Controller, I was doing some serialization to them, like the following:

This is not ideal. Not very DRY, since it would be applied in all the use cases where we need to serialize a model - I know, it’s not a model, it’s an Ecto.Schema, but please bear with me on this slip of tongue.

Even if we extract the clean method to a dedicated Module or Macro, it would still need some tune up depending on the associations existing on the model. Or we could do some AST parsing and manipulate the structure. Are you sensing the “you’re overcomplicating things” alarm here?

There should be a better way, and there is! It was one of those A-ha/face palm moments. We can fix this issue at the model definition level by leveraging the use of protocols, which is both very elegant and very Elixirish way of doing things :)

This way, whenever you Poison.encode your model structs, it will automatically whitelist the defined attributes. But how does this work? By using Protocols! Poison allows you to use the derive functionality from version 1.5 onwards. Here’s the link for the code we’re talking about. You might’ve noticed you can also take a “black list” approach, by using except instead of only.

Hope you learned something today too!

Check my other Elixir posts here.