Ecto Changeset Updates


Trying to fully wrap my head around Ecto when updating a struct value. I know this is super basic and simple; forgive my naivete :sweat_smile:

Generated a basic Phoenix / Elixir CRUD app to play with and am testing out the generated Phoenix functions in IEx. The one that I can’t seem to wrap my head around is update. Here is the function-

def update_post(%Post{} = post, attrs) do
	|> Post.changeset(attrs)
	|> Repo.update()

Here is the schema changeset

  def changeset(post, attrs) do
    |> cast(attrs, [:title, :body])
    |> validate_required([:title, :body])

Let’s say I have this existing post-

    __meta__: #Ecto.Schema.Metadata<:loaded, "posts">,
    body: "My very first Post!",
    id: 1,
    inserted_at: ~N[2022-09-21 03:21:59],
    title: "A great post",
    updated_at: ~N[2022-09-21 03:21:59]

How can this post be updated in IEx using the existing Phoenix generated function above? I don’t quite understand how to select and match on the struct entry for the first value to feed to update_post/2

For example, I’m trying-

iex(9)> post = %{body: "My very first Post!", title: "A great post"}
iex(10)> Posts.update_post(post, %{body: "updated", title: "updated"})
** (FunctionClauseError) no function clause matching in BlogApp.Posts.update_post/2

    The following arguments were given to BlogApp.Posts.update_post/2:

        # 1
        %{body: "My very first Post!", title: "A great post"}

        # 2
        %{body: "updated", title: "updated"}

    Attempted function clauses (showing 1 out of 1):

        def update_post(%BlogApp.Posts.Post{} = post, attrs)

    (blog_app 0.1.0) lib/blog_app/posts.ex:70: BlogApp.Posts.update_post/2

I’m just not grasping how to match the function clause!

Thanks for any help! :slight_smile:

I’m still learning elixir and phoenix but it seems you are passing a map instead of a struct Post to update post


post = %{body: "My very first Post!", title: "A great post"}


post = %Post{body: "My very first Post!", title: "A great post"}

will match in

def update_post(%Post{} = post, attrs) do

Great catch! :person_facepalming: Also realized after the fact I wasn’t supplying the primary key (id) for the existing post.