Storage Drive

Implement a drive storage solution where your users can view and manage their files in a directory structure.

Level: Hard
12
746
1

JavaScript helpers

Add a global event listener for "my_app:open" . This is used to trigger file downloads in a new tab when users click on files in the drive interface.

Modify existing Storage context

Update the call to Object.insert_assocs_multi/3 in the existing Storage context to accept the :directory option. This allows uploads to be associated with a specific directory.

Drive sub-context

The MyApp.Storage.Drive sub-context handles all directory-related operations. Key functions include:

Directory schema

The Directory schema has a name , optional parent_id for nested directories, and deleted_at for soft-deletion.

The module includes an advanced feature: recursive common table expressions (CTEs). The recursive_directory_tree_query/4 function provides a functional interface for querying directory hierarchies. It supports two traversal directions:

This is used for breadcrumb navigation (finding all parents) and authorization (checking if a user owns any directory in the hierarchy).

DirectoryUser schema

The DirectoryUser schema defines ownership between directories and users. This is a many-to-many structure that could support shared directories with multiple owners.

The belongs_to_user_query/2 function uses the recursive CTE to check if a user owns a directory or any of its ancestors. This means granting access to a parent directory automatically grants access to all descendants.

ObjectDirectory schema

The ObjectDirectory schema links files to directories. An object should typically belong to only one directory at a time.

Functions include:

Update existing Object schema

The Object schema's insert_assocs_multi/3 function is extended to handle the :directory option, calling ObjectDirectory.insert_for_directory_multi/2 to create the association.

Drive LiveView

The DriveLive module implements a complete file management interface. Despite its apparent complexity, it provides significant functionality with relatively little code:

The row_items/1 function normalizes directories and files into a common format for the table, including a back navigation item when inside a directory. Each item type gets appropriate icons and click handlers.

The LiveView uses handle_params/3 to load the current directory (if any), breadcrumbs, child directories, and files based on the URL.

Drive components

Components specific to the drive interface:

These can be reused by other features and extended as the interface grows.

Directory form component

A LiveComponent for creating and editing directories. It handles three actions:

After successful operations, it sends a message to the parent LiveView to refresh the UI.

Router updates

New routes for the drive interface:

All routes require authentication.

Migration

Creates three tables:

Indexes are added for foreign keys to optimize queries.