Live Uploads

Let's learn how to add a file upload feature to your Phoenix application.

The LiveView framework supports the most common features that single-page apps must offer their users, including multipart uploads. LiveView can give us highly interactive file uploads, right out of the box.

In this lesson, we’ll add a file upload feature to our application. We’ll use LiveView to display upload progress and feedback while editing and saving uploaded files. When we’re done, we’ll have all the tools we need to handle complex forms, even those that require file uploads.

We’ll add file uploads to the ProductLive form so users can choose an image to upload and associate with the product in a database. Let’s plan this new feature first. We’ll start on the backend by adding an image_upload field to the table and schema for products. Then, we’ll update the ProductLive.FormComponent to support file uploads. Finally, the LiveView should report on upload progress and other bits of upload feedback.

Let’s get started!

Persisting product images

We’ll start in the backend by updating the products table and Product schema to store an attribute image_upload, pointing to the location of the uploaded file. Once we have our backend wired up, we’ll be able to update our LiveView’s form to accommodate file uploads.

We’ll start at the database layer by generating a migration to add a field, :image_upload to the products table.

First, generate our migration file by typing the following command in the terminal below:

Press + to interact
mix ecto.gen.migration add_image_to_products
Terminal 1
Terminal
Loading...

This creates a migration file for us. After adding content to the change function, our migration file should look like this:

Press + to interact
defmodule Pento.Repo.Migrations.AddImageToProducts do
use Ecto.Migration
def change do
alter table(:products) do
add :image_upload, :string
end
end
end

This code will add the new database field when we run the migration. Let’s do that now. Go to the terminal below and type in the following command:

Press + to interact
mix ecto.migrate

The output should look something like this:

Press + to interact
...
[info] == Running 20201231152152 Pento.Repo.Migrations.AddImageToProducts.change/0 forward
10:22:24.034 [info] alter table products
10:22:24.041 [info] == Migrated 20201231152152 in 0.0s
Terminal 1
Terminal
Loading...

This migration added a new column :image_upload, of type :string, to the products table, but our schema still needs attention.

To do so, we updated the corresponding Product schema by adding the new :image_upload field to the schema function in pento/lib/pento/catalog/product.ex, like this:

Press + to interact
defmodule Pento.Catalog.Product do
use Ecto.Schema
import Ecto.Changeset
schema "products" do
field :description, :string
field :name, :string
field :sku, :integer
field :unit_price, :float
field :image_upload, :string
timestamps()
end
end

Remember, the changeset cast/4 function must explicitly allowlist new fields, so we added the :image_upload attribute as well like this: ...