I’m using a changeset to validate query params for search filters. I would only like to apply changes in params only when they’re valid. Is there a natural way to ignore or drop invalid changes in a changeset so that invalid query parameter values casted in my filter changeset are simply ignored or dropped?
It currently looks rougly like this:
def search_query(%Ecto.Changeset{} = filters, params) do
filters
|> cast_and_validate(params)
|> Ecto.Changeset.apply_action!(:update) # except partially apply valid changes here
# ...
end
I don’t think there’s any function in Ecto.Changeset doing what you want directly, but that should be pretty simple. You could do, once you’re changeset went through the cast and validations (untested):
changes = Map.drop(changeset.changes, Keyword.keys(changeset.errors))
Changeset.changes(filters, changes) # set the valid changes without going through validations again
If you’d like to keep into the original pipe, and using Elixir 1.12 and newer, using the wonderful then/2 (also untested):
def search_query(%Ecto.Changeset{} = filters, params) do
filters
|> cast_and_validate(params)
|> then(&Ecto.Changeset.changes(filters, Map.drop(&1.changes, Keyword.keys(&1.errors))))
|> Ecto.Changeset.apply_action!(:update)
# ...
end
Note i assume that filters does not already contains changes, since Changeset.changes does not replace but rather merge into the existing.