Understand ecto cast

phoenix

#1

Hi all
I am trying to understand how Ecto.Changeset the cast function works.
Function description:

cast(data, params, allowed)

The first parameter is the given data, the second parameter is going the change the given data and the third parameter?

Thanks


#2

A list of symbols. Those symbols map to keys in data and params, to whitelist fields that will be touched. Anything not on whitelist is ignored.


#3

I have following example

Ecto.Changeset.cast(%User{}, %{name: “Jose”, username: “josevalim”}, [:name])

Only the name is going to be changed or inserted?

Thanks


#4

Yes only one.

The documentation is pretty clear I think, did you read this?
https://hexdocs.pm/ecto/Ecto.Changeset.html#cast/3


#5

Yes, I did read documentation but it is not clear, I read for sure several times. Sorry.


#6

No this means the wording of documentation may be not good enough.

You can try improving it and sending PR to elixir if you feel like contributing :wink:


#7

Maybe is my english not good enough too :slight_smile:

By the way, on this example:

Ecto.Changeset.cast(%User{}, %{name: “Jose”, username: “josevalim”}, [:name])

Only the field name is going to change and others will be rejected?

THanks


#8

Yes, that is correct.


#9

Thanks so much. :slight_smile:


#10

Hi, I’m confused. If that’s the case why in the documentation example (below), new_changeset.params returns {title: "Foo"} instead of {title: "Hello"} ? Only the :body field should have been added in the returned changeset.

iex> changeset = cast(post, %{title: "Hello"}, [:title])
iex> new_changeset = cast(changeset, %{title: "Foo", body: "Bar"}, [:body])
iex> new_changeset.params
%{"title" => "Foo", "body" => "Bar"}

#11

because in the docs they are composing a changeset

changeset = cast(post, %{title: “Hello”}, [:title])

already allows :title


#12

cast/3's signature is cast(data, params, allowed). In this case new_changeset.params is the second argument passed to cast/3. Maybe new_changeset.changes is what you’re looking for?

iex> data = %{body: "Body", title: "Title"}                                                                    
iex> types = %{body: :string, title: :string}                                                                  
iex> changeset = {data, types} |> Ecto.Changeset.change                                                        
iex> new_changeset = changeset |> Ecto.Changeset.cast(%{body: "New Body", invalid_key: "Invalid Key"}, [:body])
iex> new_changeset.changes
%{body: "New Body"}
iex> new_changeset.params
%{"body" => "New Body", "invalid_key" => "Invalid Key"}

#13

I had the exact same confusion on this example. I suggest breaking it up into two examples, one that starts with a struct and behaves the way https://elixirforum.com/users/aseity and I thought it would (with a result of %{“title” => “Hello”, “body” => “Bar”})
And then another that clarifies that you can preset allowed fields by starting with a changeset that already allows it.


#14

[replying in the thread, I hope]
I had the exact same confusion on this example. I suggest breaking it up into two examples, one that starts with a struct and behaves the way https://elixirforum.com/users/aseity and I thought it would (with a result of %{“title” => “Hello”, “body” => “Bar”})
And then another that clarifies that you can preset allowed fields by starting with a changeset that already allows it.


#15

I had the same confusion as @JohnB with this example. I did not realize that “allowed” field names were accumulated inside the changeset until reading this thread.