

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:
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.
If you would like to make a comment, please fill out the form below.
| Cox packages ||| Verizon Bundles ||| Comcast promotional offers |
dddd
i have used this multiple file upload with ruby on rails but while cresting an empty row is created in the database
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
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
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
}