How can I refresh a model?

I have 2 models in Ecto: Parent and Child.

Parent has many Child ones, and Child belongs to Parent.

And I have something like this:

parent_id = 123
parent = Repo.get(Parent, 123)

child_id = 456 # it belongs to Parent
child = Repo.get(Child, child_id) |> Repo.delete()

# how can I now refresh parent and its "child_items"

As you can see, I’ve deleted one Child from Parent. How can I now refresh “parent” so that the amount “child_items” reflects this change? Should I retrieve it one more time from a database?

Or perhaps I should’ve deleted the child via parent? How?

3 Likes

You can just

parent = Repo.get(Parent, parent.id)

If this is something you want to do a lot then I’d suggest adding a function to your MyApp.Repo module that looks like:

def reload(%module{id: id}) do
  get(module, id)
end
5 Likes

what’s the difference with my code?

Should I retrieve it one more time from a database?

What @benwilson512 means is that you have to get it after you’ve deleted the child. So add the line afterward to have parent point to the new updated Parent struct.

As you may know, everything in Elixir is immutable so there’s no such thing as reloading data like in Rails. So everywhere you store a reference to the parent will still refer to the “old” version after reloading it all these places.

1 Like

I know, and that’s what I asked – will I have to retrieve it again from a db?

Yes. My example retrieves it from the DB because that’s what you have to do.

You could use cast_assoc or put_assoc to modify the children via the Parent changeset. Then you shouldn’t need to retrieve from DB again.

If you don’t need changesets (e.g. because you’re not validating user input), then of course you can just update the parent yourself, something like:

parent = %{parent | child_items: Enum.filter(parent.child_items, fn x -> x.id != child_id end)}

(your code sample doesn’t show it, but I’m assuming you’re preloading child_items)

1 Like

then why didn’t you reply “yes” instead?

1 Like

this won’t update it, it’ll only filter them. why? how exactly can I update child models?

Would Ecto.Repo.preload/3 with the force: true option passed in be a more modern/idiomatic candidate to a solution for this problem?

4 Likes

thanks @mariusbutuc, this worked for me :slight_smile:

1 Like

Didn’t know this existed! Thanks!

1 Like