How do you handle file upload in rail without attaching them to active record ?
I just want to write the files to the dis开发者_如何学Ck.Thanks,
If I understand correctly what you need then the most simple example would be this:
The controller:
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
The view:
<% 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 %>
This would let you upload any file without any checks or validations which in my opinion isn't that usefull.
If I would do it myself then I would use something like validatable gem or tableless gem just tableless is not supported anymore. These gems would allow you to validate what you're uploading to make it more sane.
You can just move the temporary file to destiny path using 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
The Tempfile
documentation shows an example that's equivalent to Rytis's code, which is fine most of the time. But when you call tempfile.read
, Ruby is reading the whole file as a single chunk into memory, which is sub-optimal.
However, FileUtils
provides a copy_stream
method, and IO
, at least in Ruby 2.0, provides a copy_stream
implementation that handles writing directly to a filepath (FileUtils.copy_stream
requires File-like objects on both sides, or so say the docs).
In my case, I was initiating a large multi-file upload via AJAX, and wanted to avoid reading the whole file(s) into Ruby's memory before writing to disk.
In the example below, params[:files]
is an Array
of ActionDispatch::Http::UploadedFile
instances, and local_filepath
is a string pointing to a non-existing file in an existing directory. For brevity, I'll assume I'm only uploading one file:
IO.copy_stream(params[:files][0].tempfile, local_filepath)
The ActionDispatch::Http::UploadedFile
instance has a .tempfile
field that's just a regular Tempfile
instance.
I'm not actually sure that Ruby still isn't reading the whole file into memory—I didn't benchmark anything—but it's a lot more possible than it is with the localfile.write(tempfile.read)
syntax.
tl;dr: IO.copy_stream(your_tempfile, your_disk_filepath)
is more concise, if not faster.
You could try using the Rails plugin Attachment_fu to handle file uploads. It allows you to save uploads to the file system instead of the database.
精彩评论