Cast Assoc code
cast_assoc(changeset, name, opts \ [])
Casts the given association with the changeset params
This function should be used when working withe the entire association at once(and not a single element of a many-style association) and using data external to the application.
When updating the data, this function requires the association to have been preloaded in the changeset struct. Missing data will invoke the :on_replace
behaviour defined on the association. Preloading is not necessary for newly built structs.
The parameters for the given association will be retrieved from changeset.params
. Those parameters are expected to be a map with attributes, similar to the ones passed to cast/4
. Once parameter are retrieved, cast_assoc/3
will match those parameters with the associations already in the changeset record
For example, imagine a user has many addresses relationship where post data is sent as follow
1 | %{"name" => "John Doe", "addresses" => [ |
and then
1 | user |
Once cast_assoc/3
is called, Ecto will compare those params with the addresses already associated with the user and acts as follows:
If the parameter does not contain an ID, the parameter data will be passed to
changeset/2
with a new struct and become an insert operationIf the parameter contains an ID and there is no associated child with such ID, the parameter data will be passed to
changeset/2
with a new struct and become an insert operationIf the parameter contains an ID and there is an associated children with such ID, the parameter data will be passed to
changeset/2
with the existing struct and become an update operation.If there is an associated child with an ID and its ID is not given as parameter, the
:on_replace
callback for that association will be invoked
Code
1 | `cast_assoc/3` is useful when the associated data is managed alongside the parent struct, all at once. |
1 | def cast_assoc(changeset, name, opts \\ []) when is_atom(name) do |
Put Assoc
As alternative to cast_assoc/3
cast_assoc/3
is useful when the associated data is managed alongside the parent struct, all at once.
If each side of the association is managed seperately, it is preferable to use put_assoc/3
and directly instruct Ecto how the association should look like.
For example, imagine you are receiving a set of tags you want to associate to an user. Those tags are meant to exist upfront. Using cast_assoc/3
won’t work as desired because the tags are not managed alongside the user. In such cases, put_assoc/3
will work as desired.
1 | %{"name" => "John Doe", "tags" => ["lieanr"]} |
and then:
1 | tags = Repo.all(from t in Tag, where: t.name in ^params["tags"]) |
Example
Build_Assoc
Gen an instance with foreign key
1 | iex> post = Ecto.build_assoc(user, :posts, %{header: "Clickbait header", body: "No real contet"}) |
Put_Assoc
Add association to changeset which is not persisted
1 | iex> post_changeset = Ecto.Changeset.change(post) |
Conclusion
cast_assoc
when you want to cast external parameters, like the ones from a form, into an association.
put_assoc
when you already have an association struct
build_assoc
receive an existing struct(for example user
), that was persisted to the database, and builds a struct(for example post
, based on its association(for example :posts
), with the foreign key field(for example user_id
).