Don’t be scared of using the same table for different schemas in Ecto

Don’t be scared of using the same table for different schemas in Ecto

Back when phoenix 1.4 was released and contexts were introduced a lot of questions arose around where to put what. For example, if I have an authentication layer for a blogging engine, should the user schema be put in the authentication context or in the blog context?

When you think about it a user has to be in the authentication layer as it is the user that we’re authenticating, but it also has to be part of the blogging engine as users should be authors of articles.

This creates a bit of a problem as wherever we decide to put the user schema, it’ll depend on things in the other context. While this doesn’t seem to be such a big deal it will make it harder to separate if we ever want to extract the authentication layer to its own service. Unless…

Defining multiple schemas on the same database table

We often tend to think that one table in our database refers to one model, or one schema depending on the pattern of our choosing. If we were to talk about things like we do in privacy, we’d probably agree on the fact that we shouldn’t make more information available than the absolute minimum that is required to do a specific task.

If we would apply that to our codebase we’d pretty come to the conclusion that an authentication layer does not have to know about which articles a certain user has written. At the same time a blog shouldn’t have access to the encrypted password of our user.

Since an Ecto schema only operates on properties that are explicitly being set in the schema definition we can isolate the bare minimum of data in different our different contexts bu simply defining them as separate schemas:

defmodule Authentication.User do
  use Ecto.Schema

  schema "users" do
    field :email
    field :password
  end
end
defmodule Blog.Author do
  use Ecto.Schema

  schema "users" do
    field :first_name
    field :last_name
    has_many :articles
  end
end

By doing this we can keep the different parts of our system fully isolated and layer our application in an onion similar API. This way we as developers won’t have to know anything about the internals of another context.