Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTML5 file drag-and-drop upload with Ruby on Rails

In my Ruby on Rails app, I have a simple file upload button that I'm trying to replace with a drag and drop box using the File/FileReader APIs in HTML5, using this tutorial specifically. As is, I use a Ruby script to upload the file to my public/data folder. I'm not sure how to integrate the drag-and-drop script with that. My idea was to make the file upload button I had already hidden, and use Javascript to set its value to the path of the drag-and-dropped image when the user tries to submit.

However, when I try to submit I get the error:

File name too long - public/data/data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAABkAAD/4QMtaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNj....

because the temporary file storage name given by HTML5 is just too long, I guess.

I tried concatenating the string to the first 60 characters and then it gave the error:

No such file or directory - public/data/data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAA

In any case, the file is not getting added to public/data folder.

My HTML:

<%= form_tag( { :action => 'create' }, :multipart => true ) %>
<div id="dropbox"><span id="droplabel">Drop file here...</span></div>
<img id="preview" alt="[ preview will display here ]" />

<%= hidden_field_tag :uploadfile, :id => "uploadfile", :name => "uploadfile" %>
<br /><br />
<div id="submit">
<%= submit_tag( "Upload file" ) %>
</div>

Ruby:

def create
    name = params[:uploadfile]
    directory = "public/data"
    path = File.join(directory, name)
    File.open(path, "wb") { |f| f.write(params[:uploadfile].read) }
     @project = Project.new({:filename => name, :location => path})

    respond_to do |format|
      if @project.save
        format.html { redirect_to @project, notice: 'Project was successfully created.' }
        format.json { render json: @project, status: :created, location: @project }
      else
        format.html { render action: "new" }
        format.json { render json: @project.errors, status: :unprocessable_entity }
      end
    end
  end

and JS:

$("#submit input").click(function() {
    $("#uploadfile").val($("#preview").attr("src"));
});
like image 962
user1436111 Avatar asked Oct 08 '12 01:10

user1436111


1 Answers

The problem looks like you are sending the file as a Base64 encoded Data URL, which is fine, but the filename doesn't go along with it when you POST to the server. You may want extract the filename before converting the file to a Data URL so you can send it along with the file in the params. Or, create a new filename (UUID) like Madao suggested.

This should at least fix your filename problem:

def create
    ##
    file = params[:uploadfile]
    name = params[:filename] || SecureRandom.uuid
    ##
    directory = "public/data"
    path = File.join(directory, name)
    File.open(path, "wb") { |f| f.write(file.read) }
    @project = Project.new({:filename => name, :location => path})

    respond_to do |format|
      if @project.save
        format.html { redirect_to @project, notice: 'Project was successfully created.' }
        format.json { render json: @project, status: :created, location: @project }
      else
        format.html { render action: "new" }
        format.json { render json: @project.errors, status: :unprocessable_entity }
      end
    end
  end
like image 168
Levi V Avatar answered Nov 14 '22 08:11

Levi V