I’m trying to model something in Ecto where records share a few common fields, but depending on a type, they have completely different additional fields.
Roughly:
- there’s an
itemstable with the common stuff (type,same_field, etc.) - and then separate tables for each type (
items_a,items_b) - these subtype tables use the same
idas the parent (so 1:1, PK = FK)
So everything is still one logical collection, just split across tables to avoid a lot of nullable columns and to keep proper DB constraints.
In Ecto I’m using has_one + cast_assoc, and dispatching based on the type.
I’m wondering:
- does this approach fit well with Ecto, or is it something people generally avoid?
- is there a more idiomatic way to solve this without collapsing everything into one table or using JSON?
- are there any gotchas with this setup (especially around inserts or preloading)?
Example changeset:
def changeset(item, attrs) do
item
|> cast(attrs, [:type, :category, :owner_id])
|> validate_required([:type, :category, :owner_id])
|> cast_subtype()
end
The whole idea is to keep validation at the database level as much as possible, not just in changesets.






















