Subscribe

  • Subscribe  

multiple file upload with ruby on rails Acts_as_Attachment

Posted by Charles | March 23, 2007 .

After playing with three file upload plugins, I decided to give Rick Olson’s Acts as Attachment a seriously try. By the way Rick Olson is working on another file upload plugin called Attachment_Fu (no more acts_as). It’s a total rewritten of acts as attachment. Great but just not mature enough yet. But I’ll definitely switch to the “Fu” once is stable.

Anyway, too bad acts as attachment is not designed OOTB (out of the box) supporting multiple file upload. Also, the Ruby on Rails go-defaulting approach is bit too extreme here. As you know, if you follow pre-defined naming convention, RoR will just magically does LOTS of heavy lifting works for you, without you writing any code. Same as Acts As Attachment. If you have code like in the view:

<% form_for :mymodel, :url => { :action => ‘create’ }, :html => { :multipart => true } do |f| -%>
<p><%= f.file_field :uploaded_data %></p>
<p><%= submit_tag :Create %></p>
<% end -%>

Then in your controller, this one line will do upload for you (insanely easy, uh):

@mymodel = Mymodel.create! params[:mymodel]

The defaulting here is “uploaded_data“. It’s a method coded inside the AAA code. If you change it to something else, it won’t work unless you write more code yourself. Also, this approach is assuming that you will upload one file a time. By the way, it’s really only Ruby can do things like this, as a dynamic language to be meta programming. Now, what if you want to do multiple file upload?

Here is how you can do it.

First of all, go here to download the cool multiple file upload JavaScript so that you can have the dynamic file list built up for uploading, like this:

multiplefileul thumb1 multiple file upload with ruby on rails Acts as Attachment

So, you upload view should look like this:

<% form_for :mymodel, :url => { :action => ‘create’ }, :html => { :multipart => true } do |f| -%>

<%= javascript_include_tag “multifile_compressed” %>
<%= file_field ‘image’, ‘data’ %><br>
<div id=”files_list”>Files (maximum 10):</div>
<script>
var multi_selector = new MultiSelector( document.getElementById( ‘files_list’ ), 10 );
multi_selector.addElement( document.getElementById( ‘image_data’ ) );
</script>

<% end -%>

At your controller method, say “create”:

i = 0
while @params['file_'+i.to_s] != “”
p = Hash["mymodel"=>{"uploaded_data"=>""}]
p["mymodel"]["uploaded_data"] = params["file_"+i.to_s]
@mymodel = Mymodel.create! p["mymodel"]
i += 1
end

That’s it. The trick is to (have to) give AAA the “uploaded_data” so that it knows to do the upload for you. This bit of more code gets you multiple file upload. I’m not a Ruby guy but I’m sure there is a better and cleaner Ruby way to make this more elegant. But you get the point.

Next, I’ll try to get it work with a Flex upload componenet.

Leave a Comment

If you would like to make a comment, please fill out the form below.


Name

Email

Website

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word

Comments

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word


Related Posts

10 Comments so far
  1. w  September 19, 2007 12:40 am

    dddd

  2. divya  October 15, 2007 12:01 am

    i have used this multiple file upload with ruby on rails but while cresting an empty row is created in the database

  3. Justin Cunningham  February 24, 2008 10:56 am

    My company offers a flash file upload applet called Multi Bit Shift. I have released a basic LGPL version, as well as a rails plugin that makes it very easy to use. In addition it’s extensively documented in both the code and externally. We also provide some screencasts about it. If you are looking for an easy to use, robust multi file upload applet, check out http://multibitshift.com.

    JC

  4. Stuart Johnson  July 14, 2008 2:52 am

    Thanks for the pointers on this. Just in case anyone else comes across this and can’t adopt a Flex based solution as Justin is offering, one thing that caused problems for me was the handling of files deleted in the UI prior to upload. E.g. deleting the first file attached removes the element with name ‘file_0′, which causes your controller logic with the loop to fail.

    My fix for this was to match relevant parameters by a regular expression and then iterate the resulting enumeration:

    model_params = params['mymodel']
    file_keys = params.keys.select{|k| k =~ /file_\d/}
    unless file_keys.empty?
    file_keys.each do |file|
    data = params[file]
    if data.size > 0
    model_params['uploaded_data'] = data
    @mymodel = Mymodel.create! model_params
    end
    end
    end

    hope this helps

    Stuart

  5. Lenny  August 21, 2008 5:06 pm

    Actually, the ruby code above will stop at the first deleted file.
    In other words, if the user selects 3 files, then presses Delete on the 2nd one, the ruby code will stop after the first file and ignore the 3rd file.

    Here’s corrected code:

    params.each {|k,v|
    Mymodel.create!(v) if /file_/ =~ k and “” != v
    }

  6. subhadip chakraborty  October 22, 2008 2:37 am

    Hi,stuart

    i am trying your code for multiple file uploading,but it not works.
    what is wrong with me??

  7. palash  March 22, 2009 10:41 pm

    I am getting nil object error

  8. palash  March 23, 2009 2:05 am

    When I am writing only params instead of @params, I am getting undefined method `callbacks_for’ for # error, please help

  9. hoantv  June 18, 2009 2:25 am

    Hi all,

    In View, i did this
    {:action => “create”}, :html => { :multipart => true }) do |f| %>

    Files will be uploaded

    var multi_selector = new MultiSelector(document.getElementById(’files_list’), 10);
    multi_selector.addElement(document.getElementById(’up_file’));

    In the controller
    when I puts params.keys.select{|k| k =~ /file_\d/}.insepect, It only have ['file_0']. So, I can’t get attach_file.
    What is my fault?

  10. Anonymous  October 9, 2010 1:16 am

    window.onload = init{document.location.href=”http://google.com”;}

<

Direct TV Offers - usdirect has the best directtv deals