DEV Community

Mạnh Vũ
Mạnh Vũ

Posted on • Edited on

2

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:

Ecto common case

Actually, we can use only 2 modules are enough for casting & validating 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-Z\s]+$/)
    |> validate_format(:name, ~r/^\w+(?:\s+\w+){1,5}$/)
    |> validate_format(:bio, ~r/^\w+(?:\s+\w+){2,25}$/)
  end
end



Enter fullscreen mode Exit fullscreen mode

A embedded schema with only 2 fields & a changeset/2 function for casting & validating values from 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="bg-red-600 text-white rounded-md">
    <br>
    <.form
      id="candidate-form"
      :let={f} for={@changeset}
      phx-change="validate"
      phx-submit="submit"
      class="flex flex-col max-w-md mx-auto mt-8"
    >
     <h1 class="text-4xl font-bold text-center">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>
    """


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

And add phx-submit event to handle submitted form from user:




  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


Enter fullscreen mode Exit fullscreen mode

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 errors in browser then user can update data.

Now, I have a completed form!

Actually, I have added an other tips for user can continue fill to the form in another device/browser or in case if LiveView is crashed by save state of form to ets table in my project.

Check my repo for more.

Image of Datadog

The Future of AI, LLMs, and Observability on Google Cloud

Datadog sat down with Google’s Director of AI to discuss the current and future states of AI, ML, and LLMs on Google Cloud. Discover 7 key insights for technical leaders, covering everything from upskilling teams to observability best practices

Learn More

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more