user_id = if (Map.has_key?(changeset.changes, :user_id)), do: changeset.changes[:user_id], else: sales_agent.user_id
changeset =
if (!user_id) do
validate_required(changeset, [:name])
else
changeset
end
I want to validate that this sales_agent record has a name if they don’t have a user_id .
But if the user_id is being changed, the new value will be in the changeset.changes and not in the sales_agent struct, and if it hasn’t changed it’ll be in the struct but not in changeset.changes . So I have to write this user_id = if (), do: , else: thing, but that seems like something Ecto should already be handling and I just don’t know how it’s doing it, so I have code like this all over my project and I’d like to get rid of it if I can.
Can use get_field/3 here. We do not need to save it to a variable. Also get_field will look at the changes and then in checks the data if it is already set.
You could create a private function and just use that in other changesets to keep it dry.
defp validate_name(changeset) do
if get_field(changeset, :user_id) do
changeset
else
validate_required(changeset, [:name])
end
end
If you needed to do something with the user_id you could also do it like this:
defp validate_name(changeset) do
if user_id = get_field(changeset, :user_id) do
# do something with user_id
changeset
else
validate_required(changeset, [:name])
end
end
And this will only go into the if if user_id is not nil
You could then just use it like so:
def changeset(sales_agent, params) do
sales_agent
|> cast(params, [:name, :start_date, :user_id])
|> validate_required([:start_date])
|> validate_name()
end
As long as you return a changeset, you can create pretty nice reusable functions to use in your changeset pipelines