Behaviour for generating storage paths for media files, plus a set of delegating functions that route calls to the configured implementation.
Built-in generators
PhxMediaLibrary.PathGenerator.Default—{type}/{id}/{uuid}/{filename}(the default)PhxMediaLibrary.PathGenerator.Flat—{uuid}/{filename}PhxMediaLibrary.PathGenerator.DateBased—{year}/{month}/{day}/{type}/{id}/{uuid}/{filename}
Configuring a custom generator
config :phx_media_library,
path_generator: PhxMediaLibrary.PathGenerator.DateBasedWriting a custom generator
Implement the PhxMediaLibrary.PathGenerator behaviour and configure it:
defmodule MyApp.TenantPathGenerator do
@behaviour PhxMediaLibrary.PathGenerator
@impl true
def relative_path(media, conversion) do
relative_path(media, conversion, %{})
end
@impl true
def relative_path(media, conversion, path_context) do
tenant_id = Map.get(path_context, :tenant_id, "shared")
base = Path.join([to_string(tenant_id), media.mediable_type, media.mediable_id, media.uuid])
ext = Path.extname(media.file_name)
name = Path.rootname(media.file_name)
filename = if conversion, do: "#{name}_#{conversion}#{ext}", else: media.file_name
Path.join(base, filename)
end
@impl true
def for_new_media(attrs), do: for_new_media(attrs, %{})
@impl true
def for_new_media(attrs, path_context) do
tenant_id = Map.get(path_context, :tenant_id, "shared")
Path.join([to_string(tenant_id), attrs.mediable_type, attrs.mediable_id, attrs.uuid, attrs.file_name])
end
endThen configure:
config :phx_media_library,
path_generator: MyApp.TenantPathGeneratorAnd pass context when generating paths:
PhxMediaLibrary.PathGenerator.relative_path(media, :thumb, %{tenant_id: "acme"})The path_context escape hatch
The optional path_context map lets you thread arbitrary data — such as
tenant_id, user_id, or space_id — into a custom path generator without
coupling to custom_properties or the media schema itself.
The built-in generators ignore path_context; custom generators may use it
however they like.
The 3-arity forms of relative_path/3 and for_new_media/2 are
@optional_callbacks. If your generator does not implement them, calls that
supply a path_context fall back gracefully to the 2-arity / 1-arity forms.
Summary
Callbacks
Generate a storage path for new media (before the record has been persisted).
Generate a storage path for new media with an optional path context map.
Generate the relative storage path for a media item.
Generate the relative storage path for a media item with an optional path context map.
Functions
Generate a storage path for new media (before it has been persisted).
Generate a storage path for new media with extra path context.
Get the full filesystem path for a media item (local storage only).
Get the full filesystem path for a media item with extra path context (local storage only).
Generate the relative storage path for a media item.
Generate the relative storage path for a media item with extra path context.
Callbacks
Generate a storage path for new media (before the record has been persisted).
Generate a storage path for new media with an optional path context map.
This is an optional callback. When not implemented, callers that supply
a path_context will automatically fall back to for_new_media/1.
@callback relative_path( media :: PhxMediaLibrary.Media.t(), conversion :: atom() | String.t() | nil ) :: String.t()
Generate the relative storage path for a media item.
@callback relative_path( media :: PhxMediaLibrary.Media.t(), conversion :: atom() | String.t() | nil, path_context :: map() ) :: String.t()
Generate the relative storage path for a media item with an optional path context map.
This is an optional callback. When not implemented, callers that supply
a path_context will automatically fall back to relative_path/2.
Functions
Generate a storage path for new media (before it has been persisted).
Delegates to the configured path generator.
Generate a storage path for new media with extra path context.
Falls back to for_new_media/1 if the configured generator does not
implement the optional 2-arity callback.
@spec full_path(PhxMediaLibrary.Media.t(), atom() | nil) :: String.t() | nil
Get the full filesystem path for a media item (local storage only).
Returns nil if the configured storage adapter for media.disk does not
expose a local path (e.g. S3).
Example
iex> PhxMediaLibrary.PathGenerator.full_path(media, nil)
"/app/priv/static/uploads/posts/abc-123/uuid/photo.jpg"
iex> PhxMediaLibrary.PathGenerator.full_path(media, :thumb)
"/app/priv/static/uploads/posts/abc-123/uuid/photo_thumb.jpg"
@spec full_path(PhxMediaLibrary.Media.t(), atom() | nil, map()) :: String.t() | nil
Get the full filesystem path for a media item with extra path context (local storage only).
Returns nil if the configured storage adapter does not expose a local
path (e.g. S3).
@spec relative_path(PhxMediaLibrary.Media.t(), atom() | String.t() | nil) :: String.t()
Generate the relative storage path for a media item.
Delegates to the configured path generator
(see PhxMediaLibrary.Config.path_generator/0).
Example
iex> PhxMediaLibrary.PathGenerator.relative_path(media, nil)
"posts/abc-123/uuid/photo.jpg"
iex> PhxMediaLibrary.PathGenerator.relative_path(media, :thumb)
"posts/abc-123/uuid/photo_thumb.jpg"
@spec relative_path(PhxMediaLibrary.Media.t(), atom() | String.t() | nil, map()) :: String.t()
Generate the relative storage path for a media item with extra path context.
Falls back to relative_path/2 if the configured generator does not
implement the optional 3-arity callback.
Example
iex> PhxMediaLibrary.PathGenerator.relative_path(media, :thumb, %{tenant_id: "acme"})
"acme/posts/abc-123/uuid/photo_thumb.jpg"