I am looking to validate that every key in a changeset attrs has been cast to in a changeset function.
My current approach is something like this:
def validate_fields(changeset, %{} = attrs) do
attrs
|> Map.keys()
|> Enum.filter(fn k when is_binary(k) ->
# TODO could cause atom exhaustion. Maybe convert keys in types to string instead?
not Map.has_key?(changeset.types, String.to_atom(k))
k ->
not Map.has_key?(changeset.types, k)
end)
|> Enum.reduce(changeset, fn invalid_key, acc ->
add_error(acc, invalid_key, "invalid attr", [expected_attrs: Map.keys(changeset.types)])
end)
end
Used like this:
schema "person" do
field :name, :string
embeds_many :pets, Pet
field :_private, :string
end
def changeset(person, attrs) do
person
|> cast(attrs, [:name, :dob, :job])
|> cast_embed(:pets)
|> validate_fields(attrs)
end
One issue I have is that I have ‘private‘ fields, that I do not want to be passed in as attrs, in the example above changeset(%{}, %{_private: “blah“}) would not be flagged. What I am looking for is a way to check that only fields that have been cast or cast_embed are present in the attrs, but I can’t see any way to get these out of the Changeset?
I am surprised this is not a common validator people would want, for use cases like validating JSON requests in an API.






















