I have an account table that links to an emails table, roughly as follows:
Currently, my changeset on accounts uses cast_assoc
to pull in the email:
|> cast_assoc(:emails, required: true, with: &Email.changeset(&1, &2))
But this means I need to provide the data as follows:
%{
username: "test",
password: "secret",
emails: %{email: "[email protected]"} //<- nested
}
I'm using GraphQL, and in order to support a "register" mutation of the form:
register(username:"test", password:"secret", email: "[email protected]")
I need to:
- Reformat my input in order to pass it into my changeset for ecto (nest it within emails)
- Flatten my changeset errors in order to return validation messages
Is there a way to refactor this, or to modify my changeset to un-nest the field? I'm new to elixir and ecto.
Your question touches upon different points in the application, so I'll make an assumption that you're using Phoenix >= 1.3 as well as Absinthe. That way, we can talk about what your context and your resolvers might look like.
Handling incoming GraphQL requests involves going through two levels of abstraction before reaching the changeset functions in your domain modules: first, the resolver; and then, the context module. An important good practice is that your resolver should only call context functions. The idea is to leave the resolver uncoupled from the underlying domain modules where your Ecto schemas live.
You can then use the resolver to massage your input to make it fit whatever your context function expects. Assuming your context is named
Accounts
, your resolver might look a bit like this:Which then calls this simple helper function that relies on
traverse_errors/2
to return all validation messages: