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.