7rans
Update shorthand for Access behavor
I implemented Access behavior for a struct today. Pseudo-code…
defmodule MyStruct do
defstruct data: %{}
@behaviour Access
# ... implementation of Access behavior on `data` ...
end
Then I tried:
a = %{x: 1, y: 2}
s = %MyStruct{data: a}
z = %MyStruct{ s | y: 3 }
And of course it did not work.
Sure would be awesome if it could be made to work somehow though.
Most Liked
cmo
The way to achieve that is to have two function heads, one that matches on the struct and one that matches on the changeset. You can have the calculate logic in a separate private function and just extract the fields and put the result into whatever structure in each of the function heads.
And where are you going to get the other values for the calculation, if they’re not being passed as args? Passing required arguments to functions is not an antipattern ![]()
LostKobrakai
I think one thing is missing from this discussion and that‘s the notion of violating DRY by having ways to calculate the computed value from various sources of data. Instead of trying to avoid repetition by limiting the number of inputs (only struct or only changeset) you can also keep both inputs, but delegate the business logic in question to a shared helper.
def with_computed(%Ecto.Changeset{} = cs) do
a = get_field(cs, :a)
b = get_field(cs, :b)
put_change(cs, :x, compute_x(a, b))
end
def with_computed(%Struct{} = struct) do
%{struct | x: compute_x(struct.a, struct.b)}
end
defp compute_x(a, b), do: a + b
sodapopcan
As @D4no0 said, it really sounds like you are trying to create class-like code. The problem with the code you showed us is that it just doubles down on why you think you need access. The real question is: “Why do you need a function that works on both in the first place?” The reason people are questioning you is because there shouldn’t be any reason to need to manually update a key of a schema’s struct, all changes should be done through changesets.
No such thing! Changeset constructors can look however you need to them to. The fact that cast_assoc will automagically look for a changeset/2 function is just a convenience. I won’t name names (@dimitarvp
) but some people think this in-of-itself is a mistake and the :with option should always be used. Which is just a lot of words to try and re-enforce my point.
sodapopcan
I used to feel this way! I definitely came around to them. I usually just use put_assoc for tenant-like relationships, or really just anything I don’t want the user to have control over changing, otherwise I just cast the ids directly. And I came to love cast_assoc for many types of nested relationships, but not all! But ya, we don’t have to get into this in this thread ![]()
D4no0
It is absolutely not clear what you want to do, can you show a extensive example that involves ecto changesets?
Or maybe the problem could be reformulated, it is often the case that you will try to do things the way you were used to in other languages.







