Any Simple validation like checking two fields if the same without Ecto, and Schema
Welcome,
You can do ecto without sql, but for simple task like mentionned, You can also check with your own custom validator function.
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.
2 Likes
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>
1 Like
Thanks for the response!
nice library