So I have a Client schema that belongs to a User schema, and has one Company schema (optional).
Here is the Client changeset I'm using with a registration form :
@doc false
def create_changeset(%Client{} = client, attrs) do
client
|> cast(attrs, [:qualification, :phone])
|> cast_assoc(:user, with: &User.create_changeset/2)
|> cast_assoc(:company)
|> validate_required([:qualification])
|> unique_constraint(:user_id)
end
And now here is a Context function that creates a User, Client and Company all at once.
def create_client(attrs \\ %{}) do
%Client{}
|> Client.create_changeset(attrs)
|> Repo.insert()
end
When all required data and their validation are ok on the registration form submit, the insertion succeeds and everything goes as I hope. Even when form validation fails before insertion attempt, the registration form is rendered back with all errors and populated with previously sent data...
But when insertion fails on a User database constraint (for example an already taken email) , the form is rendered back with all data and errors only for User and Client schema. All Company data are lost. This will force the client to re-enter all his Company information. Is this behaviour unavoidable?
In case it could be useful, I'm using Phauxth library for user authentication.
If you want to create company independently of the client, consider using alternatives for cast_assoc.
I don't know exactly your use case, but it looks like you want to create a company if client's data are fine and regardless of user data. Maybe you can call each changeset
for each schema explicitly without casting it in the Client.changeset
.
Also, your client doesn't need to send you again the attr
, as you already have them - even if Repo.insert
fails, you have access to changeset.params
, so you can use them with some additional logic.