Warning(Unhandled error in form submission) when validating a form with embedded resource

I have created two embedded resources (membership_purchase and member_purchase_info). They are embedded resources just for being used in a form so I can have validations more easily. Membership_purchase can have multiple member_purchase_info. (For details, please see attachments.)
attribute :member_purchase_infos, {:array, Marge.AshDomains.Members.MemberPurchaseInfo},
allow_nil?: false,
public?: true
end
attribute :member_purchase_infos, {:array, Marge.AshDomains.Members.MemberPurchaseInfo},
allow_nil?: false,
public?: true
end
Everything works fine. All validations work fine and validation messages are displayed correctly in the UI. But whenever the Marge.AshDomains.Members.Validations.ValidateAge is not passed and returning an error e.g. {:error, field: :dob, message: "Age cannot be less than 18"} , there will be a warning in the log:
[warning] Unhandled error in form submission for Marge.AshDomains.Members.MembershipPurchase.create

This error was unhandled because Ash.Error.Unknown.UnknownError does not implement the `AshPhoenix.FormData.Error` protocol.

** (Ash.Error.Unknown.UnknownError) Bread Crumbs:
> Exception raised in bulk create: Marge.AshDomains.Members.MemberPurchaseInfo.create

Age cannot be less than 18
[warning] Unhandled error in form submission for Marge.AshDomains.Members.MembershipPurchase.create

This error was unhandled because Ash.Error.Unknown.UnknownError does not implement the `AshPhoenix.FormData.Error` protocol.

** (Ash.Error.Unknown.UnknownError) Bread Crumbs:
> Exception raised in bulk create: Marge.AshDomains.Members.MemberPurchaseInfo.create

Age cannot be less than 18
The form and flow are working fine, as I am not really creating anything in the database. I just use it as a form to get data from user and then process it in the next step. So my question is how I can suppress this warning?
No description
No description
6 Replies
maccachan0009
maccachan0009OP2w ago
above is the form after AshPhoenix.Form.validate()
franckstifler
franckstifler2w ago
what does your validation look like? From what I can see, you are adding an error of class Unknown. In your validation you can return a class like the others, InvalidAttribute etc... https://hexdocs.pm/ash/error-handling.html#generating-errors
maccachan0009
maccachan0009OP2w ago
defmodule Marge.AshDomains.Members.Validations.ValidateAge do
@moduledoc """
Validates age
"""

# credo:disable-for-this-file

alias Marge.TimeUtils

use Ash.Resource.Validation

@impl true
def init(opts) do
cond do
opts[:dob_field] && is_atom(opts[:dob_field]) -> {:ok, opts}
opts[:min] && is_integer(opts[:min]) -> {:ok, opts}
opts[:max] && is_integer(opts[:max]) -> {:ok, opts}
is_nil(opts[:dob_field]) -> {:error, "Expected a `dob_field` atom for calculating age"}
true -> {:error, "Expected either `min` or `max` integer for age validation"}
end
end

@impl true
def validate(changeset, opts, _context) do
dob_field = opts[:dob_field]

dob = Ash.Changeset.get_attribute(changeset, dob_field)
min = opts[:min]
max = opts[:max]
reference_date = opts[:reference_date] || TimeUtils.get_current_date()

validate_age_with_age_range(dob, dob_field, min, max, reference_date)
end

defp validate_age_with_age_range(dob, dob_field, min, max, reference_date) do
reference_date = reference_date || TimeUtils.get_current_date()

age = TimeUtils.get_future_age_from_dob(dob, reference_date)

case {age, min, max} do
{age, _min, _max} when age < 0 ->
{:error, field: dob_field, message: "Invalid Date of Birth"}

{_age, nil, nil} ->
:ok

{_age, nil, max} ->
if(age <= max,
do: :ok,
else: {:error, field: dob_field, message: "Age cannot be greater than #{max}"}
)

{_age, min, nil} ->
if(age >= min,
do: :ok,
else: {:error, field: dob_field, message: "Age cannot be less than #{min}"}
)

{_age, min, max} ->
if(min <= age and age <= max,
do: :ok,
else: {:error, field: dob_field, message: "Age must be between #{min} and #{max}"}
)
end
end
end
defmodule Marge.AshDomains.Members.Validations.ValidateAge do
@moduledoc """
Validates age
"""

# credo:disable-for-this-file

alias Marge.TimeUtils

use Ash.Resource.Validation

@impl true
def init(opts) do
cond do
opts[:dob_field] && is_atom(opts[:dob_field]) -> {:ok, opts}
opts[:min] && is_integer(opts[:min]) -> {:ok, opts}
opts[:max] && is_integer(opts[:max]) -> {:ok, opts}
is_nil(opts[:dob_field]) -> {:error, "Expected a `dob_field` atom for calculating age"}
true -> {:error, "Expected either `min` or `max` integer for age validation"}
end
end

@impl true
def validate(changeset, opts, _context) do
dob_field = opts[:dob_field]

dob = Ash.Changeset.get_attribute(changeset, dob_field)
min = opts[:min]
max = opts[:max]
reference_date = opts[:reference_date] || TimeUtils.get_current_date()

validate_age_with_age_range(dob, dob_field, min, max, reference_date)
end

defp validate_age_with_age_range(dob, dob_field, min, max, reference_date) do
reference_date = reference_date || TimeUtils.get_current_date()

age = TimeUtils.get_future_age_from_dob(dob, reference_date)

case {age, min, max} do
{age, _min, _max} when age < 0 ->
{:error, field: dob_field, message: "Invalid Date of Birth"}

{_age, nil, nil} ->
:ok

{_age, nil, max} ->
if(age <= max,
do: :ok,
else: {:error, field: dob_field, message: "Age cannot be greater than #{max}"}
)

{_age, min, nil} ->
if(age >= min,
do: :ok,
else: {:error, field: dob_field, message: "Age cannot be less than #{min}"}
)

{_age, min, max} ->
if(min <= age and age <= max,
do: :ok,
else: {:error, field: dob_field, message: "Age must be between #{min} and #{max}"}
)
end
end
end
its returning either :ok or {:error, field: field, message: message}
franckstifler
franckstifler2w ago
Kind of strange which version of Ash are you running on? Maybe update? I have setup a simple example, and my validation returns an Ash.Error.Changes.InvalidAttribute class. Not an unknown as yours.
maccachan0009
maccachan0009OP2w ago
I tried the latest ash version, same warning. In your example, is that both of the resources are embedded resources? do you mind if you show me the example? thanks.

Did you find this page helpful?