Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add and show an error message with Phoenix.HTML.Form "With connection data"

I have a simple form with a textarea, where the user will type in (or copy'n'paste) a json string into it. The form will be sent to my controller action and I will validate the json string and if it will be ok, I will create some records and all is fine.

To send the form to my controller action I use Phoenix.HTML.Form "With connection data" at the moment and therefore I have no model/changeset.

<%= form_for @conn, @action, [as: :match], fn f -> %>
  <%= textarea f, :json, rows: 20 %>
  <%#= error_tag @changeset, f, :json %>
<% end %>

If the json is invalid for some reason, I like to render the form again and display the error message(s). error_tag is a view helper method which will display an error at a field if there's a changeset. Because of this it's commented out now.

def error_tag(form, field) do
  if error = form.errors[field] do
    content_tag :span, (humanize(field) <> " " <> translate_error(error)), class: "help-block"
  end
end

def error_tag(changeset, form, field) do
  if changeset.action do
    error_tag(form, field)
  end
end

What is a proper way to add an error so that I can display them at a form field. Do I have to add the error to @conn or f (form) or Is there another way to got?

like image 949
guitarman Avatar asked Feb 29 '16 13:02

guitarman


2 Answers

In your controller module

create a keyword list with the errors inside the action

errors = [field: "error message"]

then pass it when calling the render method

render(conn, "template.html", errors: errors)

In your view module

add a helper function to extract and format the message from the keyword list

def error_tag(errors, field) when is_list(errors) and is_atom(field) do
  case Keyword.fetch(errors, field) do
    {:ok, message} -> content_tag :span, (humanize(field) <> " " <> translate_error(message)), class: "help-block"
    :error -> html_escape("")
  end
end

In your template file

display the error message

<%= form_for @conn, @action, [as: :match], fn f -> %>
  <%= textarea f, :json, rows: 20 %>
  <%= error_tag @errors, :json %>
<% end %>
like image 96
josemrb Avatar answered Nov 13 '22 02:11

josemrb


Another approach is to create an embeded_schema in which you can define all the data model including validations without persisting into the DB, and rely on the validation/error management shipped in Phoenix. José Valim explains how to use this approach.

You just create the schema this way:

data  = %{}
types = %{first_name: :string, last_name: :string, email: :string}

changeset =
  {data, types} # The data+types tuple is equivalent to %Registration{}
  |> Ecto.Changeset.cast(params["sign_up"], Map.keys(types))
  |> validate_required(...)
  |> validate_length(...)

and then show the errors as usual:

<%= error_tag f, :first_name %>
like image 2
Rowinson Gallego Avatar answered Nov 13 '22 02:11

Rowinson Gallego