Closed lukeed closed 8 years ago
This is not an exrm issue, but has to do with the following: Your problem is that you use a module attribute, which behaves like a constant, but only at compile time.
From http://elixir-lang.org/getting-started/module-attributes.html#as-constants:
user defined attributes are not stored in the module by default. The value exists only during compilation time.
When you build a release you first compile all Elixir code into .beam files, so File.cwd!
's value will be backed in to whatever it was pointing to at compilation time, all occurrences of @root
will be replaced with the static path.
Long story short: the path at compile time is not the path you expect it to be at runtime later. Or in other words: the compilation directory and the release directory will never match.
Workaroud/Fix: Don't use module attributes for dynamic data like file or directory locations.
Suggestion: Use a (private) function or File.cwd!
directly.
defmodule Uploader do
# this can stay since it's defining a relative path to your base:
@upload_dir "priv/static/uploads"
@doc """
Handle the uploaded File.
Copies the File to `/priv/static/uploads`,
then Deletes the original copy.
"""
def move_to_uploads(file) do
case File.cp(file.path, "#{base_dir}/#{@upload_dir}/#{file.filename}") do
:ok -> File.rm!(file.path)
{:error, err} -> IO.inspect(err)
end
end
defp base_dir, do: File.cwd!
end
Also keep in mind, that due to the OTP nature of releases, your actual priv dir for your Phoenix application lives under <release dir>/lib/<application with version number>/priv
, while File.cwd!
will return the release directory, where no priv dir is present.
To avoid issues/bugs/conflicts you should consider to store the uploads completely outside of the release/application directory and make the uploads location configurable in your app.
Awesome. Was doing some digging and was arriving at a similar conclusion. Thanks!
Am now offloading to an external directory. Trying to configure Plug.Static
in a way so that the directory is served in both development and production modes. I know that I can do this easily in production with Nginx, but do you have any ideas? @bitwalker =)
You can use :code.priv_dir(:myapp)
to dynamically get the path to the given application's priv directory at runtime, that's what I would use for this kind of use case.
I'm running a Phoenix application and, for the time being, I'm locally storing file uploads.
I have a
priv/static/uploads
folder accessible to myEndpoint
.And I have an
Uploader
class that moves files from their temporary location to theuploads
directory:When I run the application without
exrm
active, files are uploaded to & read frompriv/static/uploads
, as expected.However, with
exrm
enabled, files are still uploaded to the non-released ("APP") directory:APP/priv/static/uploads
.And
exrm
is trying to read from its local directory:EXRM/lib/APP/priv/static/uploads
, which is always empty.When debugging the issue,
@root
(cwd) is always the "APP" directory path.