icecap
August 2, 2021, 9:20pm
1
I would like to insert Chatroom
, ChatroomMember
s and Message
in one go.
I have the following changeset
def create_changeset(attrs) do
%__MODULE__{}
|> cast(attrs, [:name, :room_type])
|> validate_required(@required_fields)
|> put_assoc(:chatroom_members, attrs.chatroom_members)
|> put_assoc(:messages, attrs.messages)
end
that I call as follows:
%{
room_type: :private,
chatroom_members: members,
messages: message
}
|> Chatroom.create_changeset()
|> Repo.insert()
Can we run the changesets for the associated records in put_assoc
? (I am aware this is feasible with cast_assoc
but it seems cast_assoc
requires the parent to exist ahead of time)
Have you tried it? I’d say it should work
2 Likes
As mentionned by @stefanchrobot , it should work.
You could also use Ecto.Multi and Repo.transaction .
1 Like
icecap
August 3, 2021, 3:58pm
4
defmodule Chata.Chatroom do
(...)
def changeset(attrs) do
%__MODULE__{}
|> cast(attrs, [:name, :room_type])
|> validate_required(@required_fields)
|> cast_assoc(:chatroom_members)
|> cast_assoc(:messages, with: &Message.create_changeset/2)
end
And then using it
iex(14)> members = [%{user_id: user_c.id}, %{user_id: user_d.id}]
[%{user_id: 2034370041046106112}, %{user_id: 2034370071924572160}]
iex(15)> message = [%{user_id: user_c.id, body: "hi"}]
[%{body: "hi", user_id: 2034370041046106112}]
iex(16)> Chatroom.changeset attrs
#Ecto.Changeset<
action: nil,
changes: %{
messages: [
#Ecto.Changeset<
action: :insert,
changes: %{body: "hi", user_id: 2034370041046106112},
errors: [chatroom_id: {"can't be blank", [validation: :required]}],
data: #Chata.Message<>,
valid?: false
>
],
room_type: :private
},
errors: [],
data: #Chata.Chatroom<>,
valid?: false
>
Doesn’t the error chatroom_id can't be blank
, mean a Chatroom
record (the parent) needs to exist before being able to run cast_assoc
?
That error is added by validate_required
because the attribute @required_fields
contains chatroom_id
2 Likes
icecap
August 3, 2021, 4:05pm
6
That was it, thanks. As I replied, I realized.
1 Like