Repo.update() with set attributes - returns {:ok, _user} but no query happens

I’m not sure exactly how to ask this question but I’m throwing it out there since I’m losing my mind a bit.

I’m following along with the LiveView uploads video and I think I may be missing some context.

In short, why doesn’t this work:

def update_user(user, attrs) do
  user
  |> changeset(attrs)
  |> Repo.update()
end

urls = get_list_of_photo_urls()
user = %{user | photo_urls = urls} # `user` is a fully populated struct from the database
update_user(user, %{})

I realize I’ve left out a lot of context here, and I can share more if I need to, but this is the general idea that he did in the tutorial: Updated the struct with the photo_urls, piped into a changeset as usual, the piped directly into Repo.update.

When I do this, update_user returns {:ok, _user} but no query happens. I’ve debugged the heck out this.

  • The database column exists and of the proper type
  • photo_urls is properly populated as a list before being piped into the changeset
  • changeset.data has the properly populated photo_urls key
  • I’ve tried passing along some required params as opposed to an empty map—makes no difference

I can provide more info if necessary but yeah… I’m going to keep digging but have already walked away from the problem and come back and it’s driving me a bit batty so I thought I’d post here in case anyone can help.

Thanks!

Can you post the changeset function? Is it supposed to have code that does something with data.photo_urls?

1 Like

Hi, thanks for the response!

The changeset is simply:

def changeset(user, attrs) do
  user
  |> cast(attrs, [:name, :email])
  |> validate_required([:name, :email])
end

The schema has field :avatar_urls, {:array, :string}, default: [] and, as per my code in my initial post, I’m setting avatar_urls directly on the struct before passing it to the changeset. This is as per the tutorial called out here (youtube link includes the timestamp): Phoenix LiveView Uploads Deep Dive - YouTube

I have don’t this before with inserting but this is my first time doing it in an update (and how it’s done in the video). It seems that the update call is just a no-op and returns {:ok, user}. No queries appear in the server log.

Can you IO.inspect after the changeset call? If Ecto does not think there are changes then it won’t do any SQL.

changes is empty—and that makes sense to me that it wouldn’t update and even return a successful response—the docs even call out that no-changes == no-op. But it works for Chris in that video! So I’m conffffuuuuussssed.

I’ve already cast avatar_urls in the changeset, passed it in as a param, and moved on for now… but just for now. I’m still so curious!

I guess there‘s a bug in the video for updates. Chris changes the urls on the post struct itself – which is never detected as a change – instead of creating a changeset with changed urls to pass into update_post. I stumbled over that this weekend as well.

2 Likes

…a bug or maybe an upcoming version of ecto? It would be nice to be able to do that. But I’m glad I’m not crazy. This is the first time I have ever had such an experience working in Phoenix.

For sure not. Ecto’s tracking of changes happens by comparing the base data in a changeset with whatever changes are applied. I does and can not be aware of changes you made to the base data.

I did not watch the video in detail this weekend, but maybe chris didn’t ever update the image. For creating new posts there’s no way around persisting the base data as well, which is the reason this becomes only a problem for updates.

I see—was just a guess :laughing: It’s just weird that he specifically calls out that he is doing that.

Thanks for your reply, though. I’m super relieved I’m not the only one experiencing this.

So I went to comment on the video and saw someone else already and has already discussed it here! Reviewing Phoenix LiveView Uploads Deep Dive

Sorry to tag you @chrismccord but is there any chance you can call this out in the video description? It seems some people are stumbling over it. For my case, I was following the tutorial while adding uploads to an existing project where I was starting with an existing record, so it was a while before I saw anything working. Ultimately this was not a big deal and I hope I’m not coming off as annoyed—I’m crazy thankful for your work. I’m actually trying to sell a bunch of people on LiveView (and Elixir and Phoenix in general) and I’m asking because I would hate for on-the-fence folk to experience this.

2 Likes