I’ve got this mutation going through Absinthe
mutation signup(
$email: String!
$firstName: String!
$lastName: String!
$organizationInput: OrganizationInput!
$password: String!
) {
signup(
email: $email
firstName: $firstName
lastName: $lastName
organization: $organizationInput
password: $password
) {
id
}
}
What’s important is inside $organizationInput
which is basically an input with 2 fields name
and slug
(name being required and slug optional)
The execution happens in this code
resolve fn _parent, args, _resolution ->
Bigseat.Dashboard.People.create(args)
end
Which is
def create(params = %{ organization: organization_params } \\ %{}) do
organization_changeset = %Organization{slug: Slug.slugify(organization_params.name)}
|> Organization.changeset(organization_params)
multi = Multi.new
|> Multi.insert(:organization, organization_changeset)
|> Multi.run(:person, fn _repo, %{organization: organization} ->
%Person{}
|> Person.changeset(params)
|> Ecto.Changeset.put_assoc(:organization, organization)
|> Repo.insert()
end)
case Repo.transaction(multi) do
{:ok, %{person: person}} -> {:ok, person}
{:error, _model, changeset, _changes_so_far} -> {:error, changeset}
end
end
Basically, I’ve got a transaction (multi) which contains a Person
and Organization
schema and when you’ll be creating a Person
you’ll also create an Organization
which needs a slug
and name
When transmitting slug
through the input it processes perfectly and works. But when I don’t transmit it make it via %Organization{slug: Slug.slugify(organization_params.name)}
the transaction just breaks silently without emitting error. I’ve also tried Map.merge
and checked Slug.slugify
and replaced it with a manual string I wrote, the end result is the same: it breaks.
The weirdest thing is it tells me the Organization
schema is valid, it’s the Person
one which breaks
[debug] QUERY OK db=0.7ms
rollback []
{:error,
#Ecto.Changeset<
action: :insert,
changes: %{
email: "test@test.com",
first_name: "Laurent",
last_name: "Something",
organization: #Ecto.Changeset<action: :update, changes: %{}, errors: [],
data: #Bigseat.Dashboard.Organization<>, valid?: true>
},
errors: [],
data: #Bigseat.Dashboard.Person<>,
valid?: false
>}
The fact there’s no errors ([]
) will output a false positive on GraphQL (no error but a null id), I’ve no detail on why it shows valid?: false
I’ve also compared both way of doing it and they are the same
pry(1)> IEx.Info.info(organization_params)
[{"Data type", "Map"}, {"Reference modules", "Map"}]
pry(2)> IEx.Info.info(Map.merge(%{slug: Slug.slugify(organization_params.name)}, organization_params))
[{"Data type", "Map"}, {"Reference modules", "Map"}]
I’m fairly new to the Elixir world, but what could be the problem here? Why having oganization_params = %{name: "Hello", slug: "hello"}
rather than %{ organization: organization_params }
given from the arguments of the method would change anything?
Those other examples which are either working or not disturb me:
# not working
organization_changeset = Organization.changeset(%Organization{}, %{name: "test", slug: "hello"})
# working
organization_changeset = Organization.changeset(%Organization{}, organization_params)
# organization_params contains %{name: "test", slug: "hello"} and was transmitted through the resolver
See below the changeset of both Person
and Organization
if that helps digging down the problem.
# organization.ex
def changeset(organization, attrs) do
organization
|> cast(attrs, [:slug, :name])
|> cast_assoc(:people)
|> validate_required([:slug, :name])
|> unique_constraint(:slug)
end
# person.ex
def changeset(person, attrs) do
person
|> cast(attrs, [:email, :encrypted_password, :first_name, :last_name, :is_admin, :group])
|> cast_assoc(:organization)
|> validate_required([:email, :first_name, :last_name])
end