Rails4:如何使用AJAX上传文件



我想用AJAX上传文件。在过去,我通过使用神奇的jQuery表单插件实现了这一点,效果非常好。目前,我正在构建一个Rails应用程序,并尝试"Rails方式",所以我使用Form Helper和paperclip gem来添加文件附件。

rails文档警告Form Helper不适用于AJAX文件上传:

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

很明显,没有现成的解决方案。所以我想知道最明智的做法是什么。似乎我有几个选择:

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

三者似乎都有可能。我对#3知之甚少,特别是[其他宝石]部分。我发现了两个类似的问题(这个和这个),其中提到了Pic Upload的一个名为Uploadify的分支,但这两个问题都是2年前的问题,涉及Rails 2和3(Uploadify已经好几年没有更新了)。因此,考虑到变化有多大,我认为这真的是一个全新的问题:

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

查看remotipart宝石:https://github.com/JangoSteve/remotipart——只需很少的工作就可以把你一路带到那里!

使用@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中设置RequestHeader。

FormData使用与如果编码类型设置为"0"则表单将使用的格式相同的格式;多部分/形式数据";

IMHO Rails在使用AJAX处理上传文件时并不完美,尤其是当您想要进度条时。我的建议是使用Javascript通过AJAX请求提交表单,就像您在(2)中建议的那样。如果你对Javascript感到满意,你就不会有太多问题。

我最近使用了同样的方法,使用了这个非常简单的JS库https://github.com/hayageek/jquery-upload-file我在这里写了更多的细节http://www.alfredo.motta.name/upload-video-files-with-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();
  });
});

远非完美,但在前端给你带来了灵活性。

最新更新