Phoenix contexts and ecto abstract tables
Phoenix 1.3 introduced the concept of contexts in a application. Even though it’s a simple idea on paper — structure you application in modules and functions, which belong to a related context—it’s been an eye-opener for my own projects. I think much more about how high or low level some part of my application is and where the dependencies are between those parts.
One recent result of this awareness was the addition of address handling and retail-stores into an application. Stores are a key element of that application, so they’re a rather high level element. Addresses on the other hand are just a bunch of strings and location data—as well as not really limited in usage for stores—therefore they’re rather low level.
I quickly added the two contexts retailers
and addresses
to my application as well as schemas for Store
and Address
. But when it got to adding the association between both I got kinda stuck. The Address
shouldn’t need to know about a more high level concept of stores yet a association of has_one :address, Address
on the Store
schema would mean putting a store_id
column in the addresses
table. At the same time belongs_to :address, Address
is incorrect as well.
This is where ectos abstract tables feature comes into play. It’s a way to define a low level abstract schema Address
which is not linked to any specific table. It’s simply a blueprint, which each higher level component like my Store
schema can use in combination with its own addresses table like this: has_one :address, {"store_addresses", Address}, foreign_key: :assoc_id
. So this new table can have it’s assoc_id
linking to the stores
table without interfering with any other addresses I might need to store for that application. The documentation about the feature also mentions this as being more performant and overall a better design for the database. At runtime everything stays as it was. Each Address
struct will still be the same—besides the primary key.
So being aware of those dependencies between contexts and they’re place within the application actually lead me to a better database architecture and told me that I’m working with the concept of polymorphic associations even before I had the actual use-case of sharing the address schema with multiple higher level elements.
So the TLDR would be: If neither belongs_to
nor has_one/has_many
seem to fit your use case maybe take a look at abstract tables.