Using Ecto (without Db) for validating Phoenix form

Using Ecto (without Db) for validating Phoenix form

I had a sharing session for Elixir community in Saigon about how to using Ecto without db for validating Phoenix form. Now I add this for people who just start to learn Elixir can see what can do with Ecto & Phoenix form.

For save time I just write an example for HTML form in LiveView.

As we known Ecto is very flexible library for Elixir application and people usually use Ecto like:

Actually, we can use only 2 modules are enough for cast & validate form: Ecto Changeset & Schema (you can use only Changeset module but with Schema much more convenience).

For example:
I declare Schema for Candidate module:

defmodule DemoEctoForm.Candidate do
use Ecto.Schema
import Ecto.Changeset

embedded_schema do
field :name, :string
field :bio, :string
end

def changeset(candidate, attrs \ %{}) do
candidate
|> cast(attrs, [:name, :bio])
|> validate_required([:name])
|> update_change(:name, &String.trim/1)
|> validate_format(:name, ~r/^[a-zA-Zs]+$/)
|> validate_format(:name, ~r/^w+(?:s+w+){1,5}$/)
|> validate_format(:bio, ~r/^w+(?:s+w+){2,25}$/)
end
end

A embedded schema with only 2 fields & a changeset/2 function for cast & validate values from user submitted form.

For validating use can see one required field (:name) and I add some regex for checking valid fields.

And at LiveView I defined a template:

~H””
<div class=”
bgred600 textwhite roundedmd“>
<br>
<.form
id=”
candidateform
:let={f} for={@changeset}
phx-change=”
validate
phx-submit=”
submit
class=”
flex flexcol maxwmd mxauto mt8
>
<h1 class=”
text4xl fontbold textcenter“>New Candidate!</h1>
<br>
<.input field={f[:name]} placeholder=”
Nguyen Van Great” id=”name” label=”Full Name” />
<br>
<.input field={f[:bio]} placeholder=”
example: Elixir, Phoenix, Ecto, Hòzô” id=”bio” label=”Bio“/>
<br>
<.button type=”
submit“>Add Candidate</.button>
<br><br>
</.form>
</div>
“””

I passed default changeset from mount event then use directly in form. See .form and .input

My mount event:

def mount(_params, _session, socket) do
changeset = Candidate.changeset(%Candidate{})

{:ok, assign(socket, changeset: changeset)}
end

And add phx-submit event I handle submit from user simple:

def handle_event(“submit”, %{“candidate” => candidate_params}, socket) do
changeset =
%Candidate{}
|> Candidate.changeset(candidate_params)

if changeset.valid? do
data = apply_action!(changeset, :update)
IO.puts “Candidate data: #{inspect(data, [pretty: true, struct: false])}
Ets.add_candidate(data)

socket =
socket
|> put_flash(:info, “You added a candidate!”)
|> redirect(to: ~p”/”)

{:noreply, socket}
else
changeset =
%Candidate{}
|> Candidate.changeset(candidate_params)

{:noreply, assign(socket, changeset: changeset)}
end
end

I cast data from submitted form to changeset then check if changeset is valid or not. If changeset is invalid I pass again socket for form show error in browser.

Now, I have a completed form!

Actually, I have an other tips for user can continue fill to the form in another device/browser or in case if LiveView is crashed.

Check my repo for more.

Please follow and like us:
Pin Share