Storage

Receive uploads from your users to your preferred cloud storage solution. Manage references to uploaded files and associate them with records in your business domain.

Level: Hard
19
603
1

Install deps

Install the following dependencies to get started. You can find their documentation on HexDocs.

Adding uploaders in JS

The uploaders module is imported and passed to the LiveSocket configuration. This change enables the frontend to handle file uploads using the configured uploader, which works with both local volume storage and Google Cloud Storage.

Defining uploaders

A new file exports the LiveUploader as the default uploader for the application.

Live uploader

The uploader handles the actual upload process via XMLHttpRequest. It works with both the Volume and GCS strategies from the Buckets library. The script manages the file upload lifecycle, providing progress updates through the entry.progress() callback and handling errors appropriately.

Cloud configuration

Configure your cloud module for working with file objects. In development, the local Volume adapter stores files on disk in the buckets_volume directory. The configuration specifies the bucket name, path prefix, base URL, and the uploader name that matches the JavaScript uploader.

Production configuration

For production, the configuration uses the GCS (Google Cloud Storage) adapter. You'll need to specify your bucket name, path prefix, and service account key for authentication.

Test configuration

Tests use the Volume adapter with a temporary directory to isolate test uploads from development data.

CORS

When uploading directly to Google Cloud Storage, you must apply a CORS configuration to your bucket. This example configuration allows PUT requests from localhost for development. See the GCS strategy in Buckets for details on applying this configuration.

Application

Add your cloud module to your application supervision tree. This handles any background operations required by the Buckets adapter, like keeping auth tokens fresh for GCS.

Cloud

This is your cloud module, which you'll use to manage objects. Think of this module similarly to your MyApp.Repo module, but for files. It uses the Buckets library with the configuration from your app's config.

Storage context

The Storage context encapsulates all interactions with storage objects. It provides functions for:

The soft-delete pattern allows for a grace period before permanent deletion, useful for implementing trash/recovery features.

Object schema

The Object schema stores metadata about uploaded files. Fields include:

The module provides query helpers for filtering present (non-deleted) and deleted objects, with optional duration thresholds for cleanup operations.

The insert_assocs_multi/3 function allows atomically inserting related records (like the uploader relationship) as part of the same transaction.

Helper functions include image?/1 for checking content type, signed_url/1 for generating access URLs, and remote_object/1 for reconstructing the Buckets object from database fields.

Object uploaded by user schema

This join table links objects with the users who uploaded them. It uses a composite key of object_id and uploaded_by_user_id .

The uploaded_by_user_query/2 function joins objects with this table to filter by uploader, ensuring users can only access their own uploads.

Storage controller

The StorageController handles secure file downloads. The download/2 action verifies a signature parameter before allowing access to the file.

The signature is generated using deterministic_hash/1 , which creates an HMAC using the application's secret key base. This prevents unauthorized access to files by ID alone.

The download_path/1 function generates signed download URLs for use in templates.

Storage LiveView

The StorageLive module provides an interface for uploading and managing files. It configures uploads with:

The presign_upload/2 function gets upload configuration from the Cloud module. For GCS direct uploads, you can pass additional signing options.

The handle_progress/3 callback consumes completed uploads, creating object records and updating the UI stream.

Users can view their uploads in a table showing filename, content type, preview (for images), size, and timestamp. Actions include delete (soft-delete) and download.

Storage components

Reusable components for the storage interface:

These components can be reused by other features that need file upload functionality.

Router updates

Routes for file storage are added:

In development, the buckets_volume macro mounts a route for serving files from the local volume adapter. This is placed in the dev routes block.

Migration

Creates tables for storing file metadata:

Both tables use UUID primary keys and appropriate foreign key constraints with cascade deletes.