Technology: Phoenix 1.4.9 Problem : serving uploaded images in a webpage with the "img" tag, results in some being able to load and others are not.
Tried checking the image link, but the image link (a.e. /image/1 or /image/2) loads every time without problems.
Force cache purge also doesn't prove any indication to the problem.
If people want to play with the code themselves, here is the git repo: https://github.com/WannesFransen1994/phoenix-dynamic-images
what i think is important bits of code: Controller:
def index(conn, _params) do
images = Repo.all(Image)
render(conn, "index.html", images: images)
end
def create(conn, %{"upload" => %Plug.Upload{} = up}) do
{:ok, _u} = up |> ImageContext.create_image()
redirect(conn, to: Routes.page_path(conn, :index))
end
def display(conn, %{"id" => id}) do
i = Repo.get(Image, id)
conn |> put_resp_content_type(i.content_type) |> send_file(200, Image.local_path(i))
end
ImageContext.ex
def create_image(%{filename: _, path: tmp_path, content_type: _} = upload) do
hash = File.stream!(tmp_path, [], 2048) |> Image.sha256()
with {:ok, %File.Stat{size: size}} <- File.stat(tmp_path),
data_merged <- Map.from_struct(upload) |> Map.merge(%{size: size, hash: hash}),
{:ok, upload_cs} <- %Image{} |> Image.changeset(data_merged) |> Repo.insert(),
:ok <- tmp_path |> File.cp(Image.local_path(upload_cs)) do
{:ok, upload_cs}
else
{:error, reason} -> Repo.rollback(reason)
end
end
Image schema (without the changeset etc...)
schema "images" do
field :filename, :string
field :content_type, :string
field :hash, :string
field :size, :integer
end
def local_path(%Image{} = upload) do
[@upload_directory, "#{upload.id}-#{upload.filename}"] |> Path.join()
end
The output (on the image display link) works, but when I go to the overview page where all the images with the "img" tags get generated, they randomly fail to load (sometimes they all work, sometimes none, sometimes half, sometimes one works and the others don't)
Strange thing is that when you check the logs you get the following error:
** (exit) an exception was raised:
** (File.Error) could not read file stats "uploads/images/1-user_upload_3.png": no such file or directory
while the file is there and it works when you reload, or view the image apart.
EXTRA: image of the problem. Same page, just reloaded twice:
Solution was to work with absolute paths.
Apparently Phoenix sometimes changes the current working directory, for example when code reloading, and thus the relative path fails.
Credit goes to Nobbz (Slack) and Jose Valim (Git issue).