Ecto Validations
| elixirRecently I’ve been trying my hand at building a small project with Phoenix. Most of my time learning Elixir was just spent on reading about GenServer lol. It’s nice to spend some quality time on personal projects for a change.
I’m still trying to shake the Rails bias, I suppose Rails does spoil us quite a bit. Modeling is a bit different with Phoenix. Data schemas, changesets, and repositories are still pretty exotic but I’ve hardly scraped the surface.
My first roadblock was actually validating a belongs_to
association on
the child record. Below is a summary of my findings:
An Ecto schema simply maps a data source into an Elixir struct
Setting up a belongs_to
association in the child schema does not
automatically validate its presence at the application level. However
this information is used by assoc_constraint/3
to infer the foreign key
constraint name.
assoc_constraint/3 and foreign_key_contraint/3 do not validate presence of the foreign key
These two constraints come into play once the actual database query is
made. I only assumed it’d suffice because the
Hexdocs
explicitly state not to use validate_required/3
to validate
associations.
My rationale is I don’t even want to attempt the database query if the
foreign key column is nil
. At the database level, the foreign key is
non-nullable. I ended going against the documentation and included
the foreign key in validate_required/3
.
Using changesets is not mandatory
It was kinda shocking to be able to easily insert records into the
database. I got wrecked while following along in the book I was using,
since it used Kernel.struct/2
and chained that into a repository
insert before changesets were introduced. Without using changesets,
Phoenix will throw an error…
defmodule Disc.Dawg.Release do
use Ecto.Schema
import Ecto.Changeset
schema "releases" do
field(:title, :string)
field(:cover_url, :string)
field(:description, :string)
field(:released_at, :date)
timestamps()
belongs_to :artist, Disc.Dawg.Artist
end
def changeset(release, params \\ %{}) do
release
|> cast(params, [:artist_id, :title, :cover_url, :description, :released_at])
|> validate_required([:title, :artist_id])
|> assoc_constraint(:artist)
end
end
defmodule Disc.Dawg.Grid do
alias Disc.Dawg.{Artist, Release, Repo}
@repo Repo
def insert_record(module, attrs) do
model = module |> struct(attrs)
apply(module, :changeset, [model, attrs])
|> @repo.insert()
end
end