Title
%Ecto.Multi{
names: #MapSet<["profile"]>,
operations: [
{"profile",
{:changeset,
#Ecto.Changeset<
action: :update,
changes: %{first_name: "bence32", last_name: "cccdsadsaasc"},
errors: [],
data: #XD.Accounts.Profile<>,
valid?: true
>, []}}
]
}
For deep nested struct, I would reach for get_in and/or put_in .
yeah get_in seems good, but I cant seems to get it work yet, it says nil for this
get_in(List.first(invited_user.operations), :changeset)
get_in(List.first(invited_user.operations), :changes)
Per the documentation, you shouldn’t access the Multi
internals directly. Instead, you should call to_list/1
. Then you can filter the result based on the tag of the operation you’re interested in (:profile
in your case). You can see a (limited) example in the module docs .
So probably something like this:
%Ecto.Multi{
names: #MapSet<["profile"]>,
operations: [
{"profile",
{:changeset,
#Ecto.Changeset<
action: :update,
changes: %{first_name: "bence32", last_name: "cccdsadsaasc"},
errors: [],
data: #XD.Accounts.Profile<>,
valid?: true
>, []}}
]
}
|> Ecto.Multi.to_list()
|> Keyword.fetch!(:profile)
|> elem(1)
|> Keyword.get(:changes)
3 Likes
Not tested… You could always pattern match…
%{
operations: [{"profile", {:changeset, %{changes: changes}, []}}|_rest]
}
PS: You should add 3 ` at the beginning and the end of your code, and not put this into quotes… It’s not easy to read when it’s not formatted
it looks good, but it gives argument error on this line:
david_ex:
|> elem(1)
What’s the output if you add IO.inspect()
before:
...
|> IO.inspect()
|> elem(1)
...
Look like you’re using fetch/2
instead of fetch!/2
and that your name is a string instead of an atom. This should work:
%Ecto.Multi{
names: #MapSet<["profile"]>,
operations: [
{"profile",
{:changeset,
#Ecto.Changeset<
action: :update,
changes: %{first_name: "bence32", last_name: "cccdsadsaasc"},
errors: [],
data: #XD.Accounts.Profile<>,
valid?: true
>, []}}
]
}
|> Ecto.Multi.to_list()
|> Keyword.fetch!("profile")
|> elem(1)
|> Keyword.get(:changes)
yeah, I tried this with the string, but this gives a new error:
no function clause matching in Keyword.fetch!/2
Can you show what the output of Ecto.Multi.to_list(multi)
is?
Can you please expand why you need to access the changes field inside a multi?
2 Likes
[
{"profile",
{:update,
#Ecto.Changeset<
action: :update,
changes: %{first_name: "bence32", last_name: "cccdsadsaasc"},
errors: [],
data: #XD.Accounts.Profile<>,
valid?: true
>, []}}
]
I need a user inside the multi with the new values
Oops, by using a string as a key the result of to_list/1
is no longer a keyword list… So you need this instead:
%Ecto.Multi{
names: #MapSet<["profile"]>,
operations: [
{"profile",
{:changeset,
#Ecto.Changeset<
action: :update,
changes: %{first_name: "bence32", last_name: "cccdsadsaasc"},
errors: [],
data: #XD.Accounts.Profile<>,
valid?: true
>, []}}
]
}
|> Ecto.Multi.to_list()
|> Enum.find(fn
{"profile", profile} ->profile
_ -> false
end)
|> elem(1)
|> Keyword.get(:changes)
Can you set/access this information before you put it inside the multi?
2 Likes
That’s not how you would get that. A Ecto.Multi struct is nothing but some callbacks before it’s passed to Repo.transaction
. If you need values from prev. steps in a multi use Ecto.Multi.run
or the other functions, where you can pass callbacks as arguments.
1 Like
ok so it seems like this approach is not good, even though i can access it from earlier, i dont have id etc, so i will need to do he Multi.run approach
so if i do the update in Multi.run then how do i get the user with the updated values?
Multi.run(mult, "profile", fn _repo, x ->
Repo.update(x)end)
Accounts.get_user_by_phone_number(p["phone_number"])
because this returns the old one
The argument passed into the run
call contains a map of the results up to that point by their IDs.
1 Like