20

我想用 AJAX 上传文件。在过去,我通过使用神奇的jQuery 表单插件来实现这一点,并且效果很好。目前我正在构建一个 Rails 应用程序并尝试做一些“Rails 方式”的事情,所以我使用 Form Helper 和回形针 gem 来添加文件附件。

rails文档警告表单助手不适用于 AJAX 文件上传:

与其他表单不同,制作异步文件上传表单不像为 form_for 提供 remote: true 那样简单。对于 Ajax 表单,序列化是由在浏览器中运行的 JavaScript 完成的,由于 JavaScript 无法从您的硬盘读取文件,因此无法上传文件。最常见的解决方法是使用不可见的 iframe 作为表单提交的目标。

显然没有现成的解决方案。所以我想知道最聪明的做法是什么。好像我有几个选择:

  1. 使用表单助手和 iframe 技巧。
  2. 使用表单助手 + 加载 jQuery 表单插件来提交文件(不确定这是否会与 Rails 的真实性令牌等一起使用)
  3. 使用表单助手 + 回形针 + [其他一些 gem] 来扩展它的功能以允许 AJAX 表单提交。

这三个似乎都是可能的。我对#3知之甚少,特别是[其他一些宝石]部分。我发现了两个类似的问题(thisthis),其中提到了 Pic-Upload 的一个名为 Uploadify 的分支,但它们都有 2 年的历史并处理 Rails 2 和 3(并且 Uploadify 多年来一直没有更新)。因此,鉴于发生了多大变化,我认为这确实是一个全新的问题:

在 Rails 4 中使用 AJAX 上传文件的最佳方式是什么?

4

3 回答 3

8

看看remotipartgem:https ://github.com/JangoSteve/remotipart - 只需很少的工作就可以让你一路走好!

于 2013-09-05T03:22:07.940 回答
3

使用@rails/ujs

查看(.html.erb):

<%= file_field_tag :file, { id: "ajax_file_upload"} %>

控制器(_controller.rb):

def update
  @record = YourModel.find(params[:id])

  respond_to do |format|
    if @record.update_attributes(params[:your_model])
      format.json { render json: { success: true } }
    else
      error_messages = @record.errors.messages.values.flatten
      format.json { render json: { success: false, errors: error_messages } }
    end
  end
end

javascript(.js)

const uploadFile = element => {
  const formData = new FormData();
  formData.append("your_model[attribute_name]", element.target.files[0]);

  Rails.ajax({
    url: "your_model/:id",
    type: "PUT",
    beforeSend(xhr, options) {
      options.data = formData;
      return true;
    },
    success: response => {
      if (response.success) {
        alert("File uploaded successfully");
      }
      else {
        alert(response.errors.join("<br>"));
      }
    },
    error: () => {
      alert("ajax send error");
    }
  });
};

const documentOnReady = () => {
  const fileField = document.getElementById("ajax_file_upload");
  if (fileField) {
    fileField.addEventListener("change", uploadFile);
  }
}

document.addEventListener("turbolinks:load", documentOnReady);

注意:使用FormData时无需在 ajax 中设置请求头。

如果编码类型设置为“multipart/form-data”, FormData使用与表单相同的格式

于 2021-06-07T17:49:58.543 回答
1

恕我直言,Rails 在使用 AJAX 处理上传文件时并不完美,尤其是在您想要进度条的情况下。我的建议是使用 Javascript 通过 AJAX 请求提交表单,就像您在 (2) 中建议的那样。如果您熟悉 Javascript,您将不会遇到很多问题。

我最近通过使用这个非常简单的 JS 库https://github.com/hayageek/jquery-upload-file使用了相同的方法,我在这里写了更多详细信息http://www.alfredo.motta.name/upload-video-文件-带有-rails-paperclip-and-jquery-upload-file/

对于使用表单上传带有标题和描述的电影的应用程序,JS 代码如下所示:

$(document).ready(function() {
  var uploadObj = $("#movie_video").uploadFile({
    url: "/movies",
    multiple: false,
    fileName: "movie[video]",
    autoSubmit: false,
    formData: {
      "movie[title]": $('#movie_title').text(),
      "movie[description]": $('#movie_description').text()
    },
    onSuccess:function(files,data,xhr)
    {
      window.location.href = data.to;
    }
  });

  $("#fileUpload").click(function(e) {
    e.preventDefault();
    $.rails.disableFormElements($($.rails.formSubmitSelector));
    uploadObj.startUpload();
  });
});

远非完美,但为您提供了前端的灵活性。

于 2015-05-24T10:23:07.897 回答