开发者

file upload without activerecord

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜