简体   繁体   English

Rails 4:如何使用 AJAX 上传文件

[英]Rails 4: How to upload files with AJAX

I want to upload files with AJAX.我想用 AJAX 上传文件。 In the past I accomplished this by using the magical jQuery form plugin and it worked great.过去,我通过使用神奇的jQuery 表单插件来实现这一点,并且效果很好。 Currently I'm building a Rails app and trying to do things "The Rails Way" so I'm using the Form Helper and the paperclip gem to add file attachments.目前我正在构建一个 Rails 应用程序并尝试做一些“Rails 方式”的事情,所以我正在使用 Form Helper 和 paperclip gem 添加文件附件。

The rails docs warn that the Form Helper does not work for AJAX file uploads: rails 文档警告表单助手不适用于 AJAX 文件上传:

Unlike other forms making an asynchronous file upload form is not as simple as providing form_for with remote: true.与其他表单不同,制作异步文件上传表单并不像为 form_for 提供 remote: true 那样简单。 With an Ajax form the serialization is done by JavaScript running inside the browser and since JavaScript cannot read files from your hard drive the file cannot be uploaded.对于 Ajax 表单,序列化是由在浏览器中运行的 JavaScript 完成的,并且由于 JavaScript 无法从您的硬盘驱动器读取文件,因此无法上传文件。 The most common workaround is to use an invisible iframe that serves as the target for the form submission.最常见的解决方法是使用一个不可见的 iframe 作为表单提交的目标。

It seems clear there's no off-the-shelf solution.显然没有现成的解决方案。 So I'm wondering what's the smartest thing to do.所以我想知道什么是最聪明的做法。 Seems like I have several options:好像我有几个选择:

  1. Use the form helper and the iframe trick.使用表单助手和 iframe 技巧。
  2. Use the form helper + load jQuery form plugin to submit the file (not sure if this will play nice with Rails's authenticity token, etc)使用表单助手 + 加载 jQuery 表单插件来提交文件(不确定这是否会与 Rails 的真实性令牌等配合使用)
  3. Use the form helper + paperclip + [some other gem] to extend it's functionality to allow AJAX form submission.使用表单助手 + 回形针 + [其他一些 gem] 来扩展它的功能以允许 AJAX 表单提交。

All three seem possible.这三个似乎都有可能。 I know the least about #3, specifically the [some other gem] part.我对 #3 了解最少,特别是 [其他一些宝石] 部分。 I found two similar questions ( this and this ) which mention a branch of Pic-Upload called Uploadify but those are both 2 years old and deal with Rails 2 and 3 (and Uploadify hasn't been updated in years).我发现了两个类似的问题( thisthis ),其中提到了一个名为 Uploadify 的 Pic-Upload 分支,但这些问题都已经有 2 年历史了,并且涉及 Rails 2 和 3(而且 Uploadify 已经多年没有更新了)。 So given how much has changed, I think this is really a whole new question:因此,考虑到发生了多少变化,我认为这确实是一个全新的问题:

What's the best way to upload files with AJAX in Rails 4?在 Rails 4 中使用 AJAX 上传文件的最佳方式是什么?

看看remotipart gem: https : //github.com/JangoSteve/remotipart - 只需很少的工作就可以让您一路remotipart

IMHO Rails is not perfect when dealing with upload files using AJAX, especially if you want a progress bar.恕我直言,Rails 在使用 AJAX 处理上传文件时并不完美,尤其是当您想要一个进度条时。 My suggestion is to use Javascript for the form submission over an AJAX request like you suggested in (2).我的建议是使用 Javascript 来通过 AJAX 请求提交表单,就像您在 (2) 中建议的那样。 If you are comfortable with Javascript you will not have many problems.如果您熟悉 Javascript,您将不会遇到很多问题。

I recently used the same approach by using this very simple JS library https://github.com/hayageek/jquery-upload-file and I wrote more details here http://www.alfredo.motta.name/upload-video-files-with-rails-paperclip-and-jquery-upload-file/我最近通过使用这个非常简单的 JS 库https://github.com/hayageek/jquery-upload-file使用了相同的方法,我在这里写了更多细节http://www.alfredo.motta.name/upload-video-带导轨的回形针和 jquery-upload-file/

For an application with a form to upload a movie with title and description the JS code looks like follow:对于具有上传带有标题和描述的电影的表单的应用程序,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();
  });
});

Far from perfect, but gives you flexibility on your frontend.远非完美,但为您的前端提供了灵活性。

Using @rails/ujs .使用@rails/ujs

view (.html.erb):视图(.html.erb):

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

controller(_controller.rb):控制器(_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) 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);

Note: No need to setRequestHeader in ajax while using FormData .注意:使用FormData 时无需在 ajax 中设置请求头。

FormData uses the same format a form would use if the encoding type were set to "multipart/form-data"如果编码类型设置为“multipart/form-data”, FormData使用的格式与表单将使用的格式相同

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM