I hope I describe the problem correctly
In a phoenix changeset I want to use a function “set_area_of_residence_type/1”
changeset
|> cast(params, [(... some stuff), :country, :area_of_residence_type, :area_of_residence])
|> validate_required([ :country, :area_of_residence])
|> validate_inclusion(:country, country_codes)
|> set_area_of_residence_type()
Where country codes is just a list of country codes
[“ZW”, “ZM”, “ZA”, “YT”, “YE”, “WS”, “WF”, “VU”, “VN”, “VI”, “VG”, “VE”, “VC”,
“VA”, “UZ”, “UY”, “US”, “UM”, “UG”, “UA”, “TZ”, “TW”, “TV”, “TT”, “TR”, “TO”,
“TN”, “TM”, “TL”, “TK”, “TJ”, “TH”, “TG”, “TF”, “TD”, “TC”, “SZ”, “SY”, “SX”,
“SV”, “ST”, “SS”, “SR”, “SO”, “SN”, “SM”, “SL”, “SK”, “SJ”, “SI”, …]
I call various functions with pattern matching
def set_area_of_residence_type(changeset = %Ecto.Changeset{ changes: %{country: "ZW"}}) do
#do stuff
end
But I want to call a function when it matches
def set_area_of_residence_type(changeset = %Ecto.Changeset{ errors: [countries: _ ]}) do
#do stuff
end
This pattern match doesn’t work. As soon as there are other errors in the errors list the match fails. The docs mention this.
Then I tried to do it with guards.
def set_area_of_residence_type(changeset) when :country in changeset.errors do
but this gives compilation error
** (ArgumentError) invalid args for operator “in”, it expects a compile-time list or compile-time range on the right side when used in guard expressions, got: changeset.errors()
Then I tried with macros. Macros are impossible to understand for me so far so I am not sure if this is correct
defmodule MySite.Models.Guards do
defmacro has_country_error(changeset) do
quote do
Keyword.has_key?(unquote(changeset)[:errors], :country)
end
end
end
and in my model file
def set_area_of_residence_type(changeset) when has_country_error(changeset) do
Now I get a new compilation error
** (CompileError) web/models/user_profile.ex:69: cannot invoke remote function Access.get/2 inside guard
Is there any way to achieve what I want?
I guess I could check with an if inside a function for the existence of :countries inside the errors list and then call the appropriate function with the appropriate name but where is the fun in that?