How do you handle file upload in rail without attaching them to active record ?
I just want to write the files to the disk.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With