Hi Pablo! Thanks for pointing this out. Looks like there have been some changes to the upload behavior that require some code changes here. I’ll outline them below and then you can look for the updated code and content in the next book release!
First off, I will mention that I don’t get that warning on my version of the code for this chapter, which is running Phoenix LiveView 0.17.5. Could you let me know what version you’re running?
Regardless, though, here is the fix:
Your handle_progress/3
function in the form component should look like this:
defp handle_progress(:image, entry, socket) do
:timer.sleep(200)
if entry.done? do
# the following line has changed
{:ok, path} =
consume_uploaded_entry(
socket,
entry,
&upload_static_file(&1, socket)
)
{:noreply,
socket
|> put_flash(:info, "file #{entry.client_name} uploaded")
# the following line has changed
|> assign(:image_upload, path)}
else
{:noreply, socket}
end
end
The upload_static_file/2
function should look like this:
defp upload_static_file(%{path: path}, socket) do
# Plug in your production image file persistence implementation here!
dest = Path.join("priv/static/images", Path.basename(path))
File.cp!(path, dest)
# the following line has changed
{:ok, Routes.static_path(socket, "/images/#{Path.basename(dest)}")}
end
And the save_product
functions should now take advantage of the new :image_upload
socket assignment and add that value to the product params that will be saved:
defp save_product(socket, :edit, product_params) do
# the following line has changed
case Catalog.update_product(socket.assigns.product, Map.put(product_params, "image_upload", socket.assigns.image_upload)) do
{:ok, _product} ->
{:noreply,
socket
|> put_flash(:info, "Product updated successfully")
|> push_redirect(to: socket.assigns.return_to)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, :changeset, changeset)}
end
end
defp save_product(socket, :new, product_params) do
# the following line has changed
case Catalog.create_product(Map.put(product_params, "image_upload", socket.assigns.image_upload)) do
{:ok, _product} ->
{:noreply,
socket
|> put_flash(:info, "Product created successfully")
|> push_redirect(to: socket.assigns.return_to)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, changeset: changeset)}
end
end
Finally, you can remove this line from the form HTML:
<%= hidden_input f, :image_upload %>
Since we’re now storing :image_upload
directly in socket assigns and pulling it out of socket assigns when its time to save the product.
One thing to note (which is new behavior I believe), is that once the upload entry has been consumed, it is removed from @upload.entries
. That is why the form file input resets. While the file input resets, the image upload is successfully stored in socket. assigns.upload
(with the new code above).
One additional change you can make to get better feedback in the UI is to render the flash info on the bottom of the form like this:
# put this within the div that contains the form
<p class="alert alert-info" role="alert"
phx-click="lv:clear-flash"
phx-value-key="info"><%= live_flash(@flash, :info) %></p>
Then, when a file is finished uploading, you should see something that looks like this:
Let me know if that works for you or if you run into any other difficulties!