【发布时间】:2010-12-13 20:36:15
【问题描述】:
如何在不将文件附加到活动记录的情况下处理文件上传?
我只想将文件写入磁盘。
谢谢,
【问题讨论】:
标签: ruby-on-rails
如何在不将文件附加到活动记录的情况下处理文件上传?
我只想将文件写入磁盘。
谢谢,
【问题讨论】:
标签: ruby-on-rails
如果我正确理解您的需求,那么最简单的例子就是:
控制器:
class UploadController < ApplicationController
def new
end
def create
name = params[:upload][:file].original_filename
path = File.join("public", "images", "upload", name)
File.open(path, "wb") { |f| f.write(params[:upload][:file].read) }
flash[:notice] = "File uploaded"
redirect_to "/upload/new"
end
end
观点:
<% flash.each do |key, msg| %>
<%= content_tag :div, msg, :class => [key, " message"], :id => "notice_#{key}" %>
<% end %>
<% form_tag '/upload/create', { :multipart => true } do %>
<p>
<%= file_field_tag 'upload[file]' %>
</p>
<p>
<%= submit_tag "Upload" %>
</p>
<% end %>
这可以让您上传任何文件而无需任何检查或验证,我认为这不是那么有用。
如果我自己做,我会使用validatable gem 或tableless gem 之类的东西,只是不再支持无表。这些 gem 可以让您验证您上传的内容,使其更加合理。
【讨论】:
File.join("public", "images", "upload") 创建directory吗?
Tempfile 文档显示了一个与 Rytis 的代码等效的示例,大多数情况下都可以。但是当您调用tempfile.read 时,Ruby 会将整个文件作为单个块读取到内存中,这是次优的。
然而,FileUtils 提供了一个copy_stream 方法,而IO,至少在 Ruby 2.0 中,提供了一个处理直接写入文件路径的copy_stream 实现(FileUtils.copy_stream 在两者上都需要类似文件的对象双方,或者说文档)。
就我而言,我通过 AJAX 启动大型多文件上传,并希望避免在写入磁盘之前将整个文件读入 Ruby 的内存。
在下面的示例中,params[:files] 是 Array 的 ActionDispatch::Http::UploadedFile 实例,local_filepath 是指向现有目录中不存在文件的字符串。为简洁起见,我假设我只上传一个文件:
IO.copy_stream(params[:files][0].tempfile, local_filepath)
ActionDispatch::Http::UploadedFile 实例有一个 .tempfile 字段,它只是一个普通的 Tempfile 实例。
我实际上并不确定 Ruby 是否仍然没有将整个文件读入内存——我没有进行任何基准测试——但它比使用 localfile.write(tempfile.read) 语法更有可能。
tl;dr:IO.copy_stream(your_tempfile, your_disk_filepath) 更简洁,甚至更快。
【讨论】:
您可以使用 FileUtils 将临时文件移动到命运路径
tmp = params[:my_file_field].tempfile
destiny_file = File.join('public', 'uploads', params[:my_file_field].original_filename)
FileUtils.move tmp.path, destiny_file
【讨论】:
您可以尝试使用 Rails 插件Attachment_fu 来处理文件上传。它允许您将上传内容保存到文件系统而不是数据库。
【讨论】: