sewer_r4t

sewer_r4t

Simple Validation without Ecto

Any Simple validation like checking two fields if the same without Ecto, and Schema

Marked As Solved

Also Liked

gutschilla

gutschilla

If it’s really just two params that shall be the same (like password and it’s repetition), one might consider a plain pattern match and a guard that assures that two fields are the same and not nil.

def some_action(conn, %{"field_1" => value, "field_2" => value}) 
when not is_nil(value) do
  # do something with value 
end
def some_action(conn, _params) do
  # render "field_1 must be equal to field_"" 
end

For JSON payloads I’d use a JSON schema to validate against.

peerreynders

peerreynders

A contrived example

# file: lib/form_demo_web/controllers/page_controller.ex
#
defmodule FormDemoWeb.PageController do
  use FormDemoWeb, :controller

  # Store user form data under conn.params["user"]

  def index(conn, params) do
    # Data to preload form with
    user = %{"name" => "Bruce", "username" => "redrapids"}

    conn
    |> update_user(user)   # add "user" to conn
    |> render("index.html")
  end

  def update(conn, %{"user" => user}) do
    case validate_user(user) do
      {:ok, user} ->
        conn
        |> update_user(user)
        |> put_flash(:info, "Updated to #{user["name"]}, #{user["username"]}!")
        |> render("index.html")

      {:error, errors} ->
        render(conn, "index.html", errors: errors)
    end
  end

  # Make data available under conn.params["user"]
  # for Phoenix.HTML.Form.form_for/4
  #
  # Plug.Conn implements Phoenix.HTML.FormData used by form_for/4
  #
  defp update_user(conn, user),
    do: Map.update!(conn, :params, &Map.put(&1, "user", user))

  defp validate_user(user) do
    errors =
      []
      |> check_value(user, :name)
      |> check_value(user, :username)

    case errors do
      [] ->
        {:ok, user}

      _ ->
        {:error, errors}
    end
  end

  def check_value(errors, user, key) do
    cond do
      Map.get(user, Atom.to_string(key), "") == "" ->
        # format expected by FormDemoWeb.ErrorHelpers.error_tag/2
        [{key, {"can't be blank", []}} | errors]

      true ->
        errors
    end
  end
end
# file: lib/form_demo_web/router.ex
#
defmodule FormDemoWeb.Router do
  use FormDemoWeb, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", FormDemoWeb do
    pipe_through :browser

    get "/", PageController, :index
    post "/", PageController, :update # <- Added to validate form data
  end
end
# file: lib/form_demo_web/views/page_view.ex
#
defmodule FormDemoWeb.PageView do
  use FormDemoWeb, :view

  def get_errors(%Plug.Conn{assigns: %{errors: errors}}) when is_list(errors),
    do: errors

  # FormDemoWeb.ErrorHelpers.error_tag/2 needs a list
  def get_errors(_),
    do: []

  def errors?(%Phoenix.HTML.Form{errors: [_ | _]}),
    # non-empty list of errors
    do: true

  def errors?(_),
    do: false
end
<!-- file: lib/form_demo_web/templates/page/index.html.eex -->
<!--
     Phoenix.HTML.Form.form_for/4
     Phoenix.HTML.Form.text_input/3
     Phoenix.HTML.Form.submit/1

     @conn --- Plug.Conn implements Phoenix.HTML.FormData protocol
     Routes.page_path(@conn, :update) --- generates the URL to PageController.update/2
     [as: :user] --- form data is stored under conn.params["user"]
     [errors: get_errors(@conn)] --- extracts the errors for the conn to include it in the Phoenix.HTML.Form struct
     errors?/1, get_errors/1 --- defined under FormDemoWeb.PageView
     error_tag/2 --- from generated module FormDemoWeb.ErrorHelpers
-->
<h1>Current User</h1>
<%= form_for @conn, Routes.page_path(@conn, :update), [as: :user, method: "post", errors: get_errors(@conn)], fn form -> %>
  <%= if errors?(form) do %>
    <div class="alert alert-danger">
      <p>Oops, something went wrong! Please check the errors below.</p>
    </div>
  <% end %>
  <div>
    <%= text_input form, :name, placeholder: "Name" %>
    <%= error_tag form, :name %>
  </div>
  <div>
    <%= text_input form, :username, placeholder: "Username" %>
    <%= error_tag form, :username %>
  </div>
  <%= submit "Update User" %>
<% end %>
<!DOCTYPE html>
<html lang="en">
  <!-- file: lib/form_demo_web/templates/layout/app.html.eex -->
  <head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>FormDemo · Phoenix Framework</title>
    <link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
  </head>
  <body>
    <main role="main" class="container">
      <p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
      <p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
      <%= render @view_module, @view_template, assigns %>
    </main>
    <script type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
  </body>
</html>

Last Post!

sewer_r4t

sewer_r4t

nice library :+1:

Where Next?

Popular in Questions Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" =&gt; #BSON.ObjectId&lt;58eb1a7a9ad169198c3dXXXX&gt;, "email" =&gt; ...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 44608 311
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New

We're in Beta

About us Mission Statement