Phoenix LiveView上的表单中的file_input为什么不返回%Plug.Upload {}? [英] Why doesn't the file_input in the form on a Phoenix LiveView return a %Plug.Upload{}?

查看:80
本文介绍了Phoenix LiveView上的表单中的file_input为什么不返回%Plug.Upload {}?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Phoenix LiveView中有一个包含 file_input 的表单.我想使用它来允许用户上传图像.我在理解表单发送给后端的内容以及如何使用它方面遇到困难.我希望图像文件具有%Plug.Upload {}表示形式,如文档中所述,但我只得到"[目标文件]" .

I have a form in a Phoenix LiveView that contains a file_input. I want to use it to allow a user to upload an image. I'm having trouble understanding what the form is sending to my backend, and what I can do with it. I expected a %Plug.Upload{} representation of the image file, as described in documentation, but instead I just get "[object File]".

请注意,我没有使用变更集来支持表单,因为我没有使用Ecto:

Note that I am not backing the form with a changeset, because I am not using Ecto:

<%= f = form_for :post, "#", phx_submit: :create_post, phx_change: :image_attach, multipart: true %>
  <%= hidden_input f, :user_id, value: @current_user.account_id %>
  <%= textarea f, :message, class: "social-post-box", placeholder: "Something on your mind?" %>
  <div class="post-submit-container">
    <%= submit "Post", class: "post-submit" %>
    <label for="post_image" class="post-submit-image"></label
    <%= file_input f, :image %      
  </div>
</form>

我在LiveView模块中有一个处理程序来处理提交的表单,当我检查图像上传时,我看到了"[目标文件]"

I have a handler in the LiveView module to handle the submitted form, and when I inspect the image upload I see "[object File]"

def handle_event("create_post", %{"post" => post_params}, socket) do
  IO.inspect post_params["image"]
  {:noreply, socket}
end

我尝试在此位置撬动,以便可以运行 i post_params ["image"] ,它说明该对象是一个位串,即只是一个二进制文件.因此,它实际上只是文本"[object File]",甚至根本没有文件吗?

I tried prying at this location so that I could run i post_params["image"], and it explains that the object is a bitstring, ie just a binary. So it's literally just the text "[object File]", and not even a file at all?

我从表格中收到什么?为什么不是%Plug.Upload {} ?如何实现将图像上传保存到本地文件系统的目标?

What is it that I am receiving from my form? Why isn't it a %Plug.Upload{}? How can I achieve my goal of saving this image upload to the local filesystem?

推荐答案

@sbacaro指出,LiveView表单尚不支持文件上传.

As @sbacaro pointed out, file uploads are not yet supported in LiveView forms.

有关此的更多信息:

我实现了一个Javascript解决方法,无需刷新页面即可手动发送表单(以便LiveView的其他部分继续正常运行).

I implemented a Javascript workaround to manually send the form without refreshing the page (so that other parts of the LiveView an continue to function normally).

但是Phoenix在LiveViews中处理CSRF令牌的方式也存在问题.事实证明,当套接字从客户端连接时,LiveView会创建一个新令牌,并且侦听来自表单的POST的控制器将无法识别此令牌.要解决此问题,您需要手动将令牌传递到LiveView.

But were also issues with the way Phoenix handled CSRF tokens in LiveViews. It turns out the LiveView creates a new token when the socket connects from the client, and this token won't be recognized by controllers listening to POSTs from the form. To workaround this you need to manually pass the token into the LiveView.

总的来说,这种解决方法可以正常工作,但我希望将来有一天,有人在这里指出文件上传已在LiveViews中获得了支持,并提供了一种更简便的方法.

Overall, this workaround works fine, but I hope that someday in the future someone will point out here that file uploads have achieved support in LiveViews and share an easier way.

我的表格现在看起来像这样.请注意csrf令牌的手动规范:

My form now looks like this. Note the manual specification of the csrf token:

<%= f = form_for :post, Routes.profile_path(UdsWeb.Endpoint, :post_social, @current_user.username), [phx_change: :image_attach, multipart: true, id: "social-timeline-form", csrf_token: @csrf_token] %>
  <%= hidden_input f, :user_id, value: @current_user.account_id %>
  <%= textarea f, :message, class: "social-post-box", placeholder: "Something on your mind?" %>
  <div class="post-submit-container">
    <%= submit "Post", class: "post-submit" %>
    <label for="post_image" class="post-submit-image"></label>
    <%= file_input f, :image %>
  </div>
</form>

我从普通的eex模板中渲染LiveView.请注意,我是在此处手动指定csrf令牌:

I render the LiveView from within a normal eex template. Note that I'm manually specifying the csrf token here:

<%= Phoenix.LiveView.live_render(@conn, UdsWeb.ProfileTimelineLive, session: %{current_user: @current_user, csrf_token: Phoenix.Controller.get_csrf_token()}, container: {:div, class: "feed"}) %>

时间轴模块具有安装功能,可将csrf令牌加载到套接字分配中:

The timeline module has a mount function that loads the csrf token into socket assigns:

def mount(%{current_user: current_user, csrf_token: csrf_token}, socket) do
  {:ok, assign(socket, current_user: current_user, csrf_token: csrf_token)}
end

用于手动控制表单提交的JS并不是很特别,但这是:

The JS for manually taking control of the form submission isn't really special but here it is:

function handleSocialTimelinePost(e) {
  e.preventDefault();
  let form = document.querySelector("#social-timeline-form");
  let formData = new FormData(form);
  let username = formData.get("post[username]");
  let request = new XMLHttpRequest();
  request.open("POST", `/profile/${username}`);
  request.send(formData);
}

document.querySelector("#social-timeline-form button.post-submit").onclick = handleSocialTimelinePost;

这篇关于Phoenix LiveView上的表单中的file_input为什么不返回%Plug.Upload {}?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆