上传文件

来源:互联网 发布:网络销售渠道有哪些 编辑:程序博客网 时间:2024/05/29 09:45

程序中一个常见的任务是上传某种文件,可以是用户的照片,或者 CSV 文件包含要处理的数据。处理文件上传功能时有一点要特别注意,表单的编码必须设为 "multipart/form-data"。如果使用 form_for 生成上传文件的表单,Rails 会自动加入这个编码。如果使用 form_tag 就得自己设置,如下例所示。

下面这两个表单都能用于上传文件:

<%=form_tag({action: :upload}, multipart: true)do%>
  <%=file_field_tag 'picture'%>
<%end %>
 
<%=form_for @persondo |f| %>
  <%=f.file_field :picture%>
<%end %>

像往常一样,Rails 提供了两种帮助方法:独立的 file_field_tag 方法和处理模型的 file_field 方法。这两个方法和其他帮助方法唯一的区别是不能为文件选择框指定默认值,因为这样做没有意义。正如你所期望的,file_field_tag 方法上传的文件在 params[:picture]中,file_field 方法上传的文件在 params[:person][:picture] 中。

5.1 上传了什么

存在 params Hash 中的对象其实是 IO 的子类,根据文件大小,可能是 StringIO 或者是存储在临时文件中的 File 实例。不管是哪个类,这个对象都有 original_filename 属性,其值为文件在用户电脑中的文件名;还有个 content_type 属性,其值为上传文件的 MIME 类型。下面这段代码把上传的文件保存在 #{Rails.root}/public/uploads 文件夹中,文件名和原始文件名一样(假设使用前面的表单上传)。

defupload
  uploaded_io = params[:person][:picture]
  File.open(Rails.root.join('public','uploads', uploaded_io.original_filename), 'wb')do|file|
    file.write(uploaded_io.read)
  end
end

文件上传完毕后可以做很多操作,例如把文件存储在某个地方(服务器的硬盘,Amazon S3 等);把文件和模型关联起来;缩放图片,生成缩略图。这些复杂的操作已经超出了本文范畴。有很多代码库可以协助完成这些操作,其中两个广为人知的是 CarrierWave 和 Paperclip。

如果用户没有选择文件,相应的参数为空字符串。

5.2 使用 Ajax 上传文件

异步上传文件和其他类型的表单不一样,仅在 form_for 方法中加入 remote: true 选项是不够的。在 Ajax 表单中,使用浏览器中的 JavaScript 进行序列化,但是 JavaScript 无法读取硬盘中的文件,因此文件无法上传。常见的解决方法是使用一个隐藏的 iframe 作为表单提交的目标。


0 0