The files of a LiveView upload, stored.
def mount(_params, _session, socket) do
{:ok,
socket
|> assign(:photos, [])
|> allow_upload(:photos,
accept: ~w(.png .jpg .jpeg .gif .webp),
max_file_size: 10_000_000,
auto_upload: true,
progress: &handle_progress/3
)}
end
defp handle_progress(:photos, _entry, socket) do
{socket, results} = Storehouse.Live.consume(socket, :photos, accept: Storehouse.Check.images())
socket =
Enum.reduce(results, socket, fn
{_entry, {:ok, file}}, socket -> update(socket, :photos, &[file | &1])
{entry, {:error, reason}}, socket -> put_flash(socket, :error, "#{entry.client_name}: #{inspect(reason)}")
end)
{:noreply, socket}
endThe size limits and the accepted types are the upload's (its accept
and max_file_size); each file is checked again on the server, by its
bytes (Storehouse.Check), and :accept refuses the types the app does
not take. See the LiveView guide.
Summary
Functions
Allows an upload (Phoenix.LiveView.allow_upload/3) whose files go to
the store in one of three ways (:mode)
Stores the finished entries of upload_name, and cancels those the
upload refused. Gives the socket and a result for each of them, in the
entries' order.
Types
@type result() :: {Phoenix.LiveView.UploadEntry.t(), {:ok, Storehouse.File.t()} | {:error, term()}}
What became of an entry: its stored file, or why it was not stored.
Functions
@spec allow(Phoenix.LiveView.Socket.t(), atom() | String.t(), keyword()) :: Phoenix.LiveView.Socket.t()
Allows an upload (Phoenix.LiveView.allow_upload/3) whose files go to
the store in one of three ways (:mode):
:direct- straight from the browser to the store, at a URL the app signed: a large file never goes through the app. The default, for a store that signs uploads (Storehouse.S3, andStorehouse.Localin development). The browser needs Storehouse's uploader (below).:stream- through the app, on to the store as each chunk comes (Storehouse.Live.Writer): with no file on the app's disk, checked as it comes, and with no CORS, as the browser sends it to the app.:server- a plain upload: to a temporary file on the app's disk, then to the store (consume/3). The default for a store that takes neither.
Either way, consume/3 gives the stored, checked files.
socket
|> Storehouse.Live.allow(:photos,
accept: ~w(.png .jpg .jpeg .gif .webp),
max_file_size: 50_000_000,
auto_upload: true,
progress: &handle_progress/3
)With :direct, the browser needs Storehouse's uploader, in app.js:
import {Uploaders} from "storehouse"
let liveSocket = new LiveSocket("/live", Socket, {uploaders: Uploaders, ...})Options
The options of Phoenix.LiveView.allow_upload/3 (but :external and
:writer), and:
:mode-:direct,:streamor:server, as above.:adapter- the store. The default isStorehouse.adapter/0; give the same toconsume/3.:cache-truestores the files under the temporary prefix, until the record that has them is saved (Storehouse.Ecto).:key- a function of the name and the claimed type that gives the key, as forStorehouse.store/2.:types,:max_pixels- with:stream, the checked types taken and the pixels at most, checked as the file comes. (With the other modes, giveconsume/3its:acceptand:max_pixels.):expires_in- with:direct, how long the browser has to start each upload, in seconds. The default is 600.
@spec consume(Phoenix.LiveView.Socket.t(), atom() | String.t(), keyword()) :: {Phoenix.LiveView.Socket.t(), [result()]}
Stores the finished entries of upload_name, and cancels those the
upload refused. Gives the socket and a result for each of them, in the
entries' order.
- An entry that is done is consumed and stored with
Storehouse.store/2(its name and claimed type are the client's), or, sent straight to the store (allow/3), checked there withStorehouse.verify_upload/2:{:ok, file}, or{:error, reason}when the check or the store refuses it (and a file refused there is deleted). - An entry with an error (too large, a type that is not accepted, too
many files) is cancelled:
{:error, reason}, the upload's (:too_large,:not_accepted,:too_many_files, …). - An entry still in progress is left alone, and has no result.
An entry is consumed once: a call before LiveView has dropped an entry that an earlier call consumed leaves it alone. So the function can run in the progress callback and in a form's change handler, with files that finish at different times.
The options are those of Storehouse.store/2, but :name and
:content_type.