Merb on AIR - Drag and Drop Multiple File Upload
Merb was originally created by Ezra Zygmuntowicz to avoid some Rails upload issues.
This is one of the things that Merb was written for. Rails doesn‘t allow multiple concurrent file uploads at once without blocking an entire rails backend for each file upload. Merb allows multiple file uploads at once.
I’ve built ‘multiple’ file uploaders for Rails sites but they always involved some slight of hand, the files appeared to be uploading all at once but they where actually queued up by Flex then handled one by one by the app (which also had the unhappy side effect of blocking any other requests to that process). I’ve been wanting to try out Adobe AIR’s file system drag and drop for a while so this is a two-fer example. You’ll need the beta version of Flex Builder 3 or the Flex 3 SDK beta if you don’t mind getting down with the command line.
In a hurry? Here’s one I made earlier (flex source in ‘).
If you haven’t before install Merb
Then create a new Merb app
and dive on in
We’ll need two folders not in a Merb skeleton, one for Flex, and one for our uploads
Create a local database called ‘merb_air_upload’ and edit dist/conf/merb_init.rb so that the database definition matches your setup
# set your db info here
ActiveRecord::Base.establish_connection(
:adapter => ‘mysql‘,
:username => ‘root‘,
:password => ‘‘,
:database => ‘merb_air_upload‘
)
Our model will be called ‘UserFile’ as ‘Upload’ and ‘File’ are reserved words, create a migration
and edit it (dist/schema/migrations/002_create_user_files.rb) to look like so
create_table :user_files do |t|
t.column :filename, :string, :null => false
end
end
drop_table :user_files
end
end
rake your db
Then create a UserFile model (dist/app/models/user_file.rb)
end
and an upload controller (dist/controllers/upload.rb)
# for testing check jer terminal
puts params.inspect
# new user file object
@upload = UserFile.new
@upload.filename = params[:Filename]
# save
if @upload.save
# create directories
dist_root = Merb::Server.config[:dist_root]
FileUtils.mkdir dist_root + “/public/uploads/“
# move
destination = dist_root + “/public/uploads//“
FileUtils.mv params[:Filedata][:tempfile].path, destination
else
false
end
#render_no_layout
end
end
That’s it for the Merb side of thing on to our AIR app, fire up Flex Builder and create a new AIR project

I like to keep my flex files in my Rails/Merb app directory

The AIR app is three files; the main MXML file (dist/app/fx/merb_air_upload.mxml), a code behind class (dist/app/fx/com/vixiom/merb_air_upload/App.as), and an upload progress component that gets repeated for each file (dist/app/fx/com/vixiom/merb_air_upload/UploadProgressComponent.mxml). Here’s the main MXML file:
It’s hooked up to it’s code behind ‘App.as’ class by the xmlns tag ) App.as extends WindowedApplication which is the base of all AIR apps:
package com.vixiom.merb_air_upload
{
import com.vixiom.merb_air_upload.UploadProgressComponent
import mx.core.WindowedApplication;
import mx.containers.VBox;
import mx.controls.Button;
import mx.events.FlexEvent;
import flash.events.*;
import flash.desktop.*;
import flash.filesystem.File;
import flash.net.*;
public
{
private var filesToUpload :Array
private var UploadProgressComponents :Array;
public var files_vb:VBox;
public var upload_btn:Button;
private var uploadURL:URLRequest;
/*
* Constructor
*/
public :void
{
addEventListener( FlexEvent.CREATION_COMPLETE, creationCompleteHandler );
}
/*
* creationComplete
*
* called when the AIR has finishe loading, sets up drag/drop event listeners reference objects
*
*/
private :void
{
addEventListener( NativeDragEvent.NATIVE_DRAG_ENTER, onDragEnter );
addEventListener( NativeDragEvent.NATIVE_DRAG_DROP, onDragDrop );
upload_btn.enabled = false;
upload_btn.addEventListener( MouseEvent.CLICK, upload );
uploadURL = new URLRequest();
uploadURL.url = “http://localhost:4000/upload“;
uploadURL.method=URLRequestMethod.POST;
filesToUpload = new Array();
UploadProgressComponents = new Array();
}
/*
* onDragEnter
*
* files have been dragged into the app
*/
private :void
{
DragManager.acceptDragDrop(this);
}
/*
* onDragDrop
*
* when files are dropped…
*/
private :void
{
DragManager.dropAction = DragActions.COPY;
var files:Array = event.transferable.dataForFormat( TransferableFormats.FILE_LIST_FORMAT ) as Array;
for each (var f:File in files)
{
addFile( FileReference( f ) );
}
upload_btn.enabled = true;
}
/*
* addFile
*
* …add then to filesToUpload array, and the file upload listeners,
* and create a progress component for each file
*/
private :void
{
filesToUpload.push( f );
var upv:UploadProgressComponent = new UploadProgressComponent();
UploadProgressComponents.push( upv );
files_vb.addChild( upv );
upv.file_lb.text = f.name;
upv.pb.source = f;
f.addEventListener( Event.COMPLETE, completeHandler );
f.addEventListener( IOErrorEvent.IO_ERROR, ioErrorHandler );
}
/*
* completeHandler
*
* a file upload is complete, remove it from filesToUpload
* and remove the upload component
*/
private :void
{
var f:FileReference = FileReference(e.target);
for( var i:uint; i < filesToUpload.length; i++ )
{
if( f.name == filesToUpload[i].name )
{
files_vb.removeChild( UploadProgressComponents[i] );
filesToUpload.splice(i, 1);
UploadProgressComponents.splice(i, 1);
}
}
}
/*
* trace any errors
*/
private :void
{
trace(“ioErrorHandler: “ + event);
}
/*
* upload!
*/
private :void
{
for each (var f:File in filesToUpload)
{
f.upload( uploadURL );
}
}
}
}
The last file is the upload progress component, it’s progress bar listens for events from each file (upv.pb.source = f; above in the addFile method)
That’s it! test your AIR app by dragging some files from the file system, once you drop them the upload progress components show a visual representation of the files, click ‘upload files’ and the files are upload all at once (for real real not for play play this time).

drag!

drop!

upload!




Like this post? subscribe to the feed.






Awesome. I have been wanting to play with Flex and Merb and now you have given me some gound to work on. Cheers
Comment by K. Adam Christensen — June 29, 2007 @ 5:37 am
Very cool. It’s awesome to see Merb getting more use. :)
Comment by Jeremy McAnally — June 29, 2007 @ 7:12 am
Hey, u once fancy jerself w/PHP…….would love to see this on php, or on the same realm CAKEPHP? :) any chance?
Comment by tomo_atlacatl — July 9, 2007 @ 3:43 pm
Tomo I know you’re smart enough to make a PHP version, the upload script is ‘cake’ so it could be done in Cake. How about a Strata version :P
Comment by Alastair — July 9, 2007 @ 7:09 pm
[…] I also ran through the Merb/AIR tutorial here: Merb on AIR - Drag and Drop Multiple File Upload. […]
Pingback by dirtystylus » Blog Archive » Locomotive on Rails, with MAMP as a Caboose — July 10, 2007 @ 12:02 pm
Yeah, I know…. I just wanted to tempt ya back to the php side :P. Strata, heh, haven’t touch dat in a while.
Comment by tomo_atlacatl — July 10, 2007 @ 2:16 pm
[…] Check out this AIR tutorial for Drag and Drop Multiple File Upload using Merb and AIR.You need Flex builder 3 Beta for this. more @ http://blog.vixiom.com/2007/06/29/merb-on-air-drag-and-drop-multiple-file-upload/ […]
Pingback by Drag and Drop Multiple File Upload with Merb and AIR | Adobe AIR Tutorials — July 26, 2007 @ 11:29 am
Great example, much appreciated and well done.
Comment by Evan Gifford — August 9, 2007 @ 2:50 pm
thanks Evan,
Let me know when flexheads.com is launched, I use Cairngorm on some larger projects but still haven’t wrapped my brain completely around it.
Comment by Alastair — August 9, 2007 @ 4:26 pm
Update for flex3 beta 2, change the line in onDrop from:
var files:Array = event.transferable.dataForFormat( TransferableFormats.FILE_LIST_FORMAT ) as Array;
to:
var dropfiles:Array = event.clipboard.dataForFormat(flash.desktop.ClipboardFormats.FILE_LIST_FORMAT) as Array;
and add
import flash.desktop.ClipboardFormats;
Comment by paul — October 2, 2007 @ 11:43 am
And if I double checked before posting I could fix my code to match the code here.
var files:Array = event.transferable.dataForFormat( TransferableFormats.FILE_LIST_FORMAT ) as Array;
to:
var files:Array = event.clipboard.dataForFormat(flash.desktop.ClipboardFormats.FILE_LIST_FORMAT) as Array;
Comment by paul — October 2, 2007 @ 11:50 am
Hi! Looks like great work! ;-) Is it possible to combine this with a rails app? I’d like to just use merb for uploading, so I’d like to be able to open the uploader from my rails app. Can anybody give me some hints on how to do that? Another thing I’m curious about is how the merb and the air application communicate with each other - I’m relatively new to web development. Also does anybody know about how to add a button to the AIR app for adding files for uploading, using a “traditional” file dialogue? And are there any problems with deploying a rails app that also has a MERB part?
Comment by Nico — October 10, 2007 @ 1:26 am
Very nice.
Can this work with an HTTPS upload URL?
Thanks, Gerry
Comment by Gerry McLarnon — October 24, 2007 @ 2:05 am
Gerry,
I haven’t tried it with HTTPS, I know with Flex the Flash player there are special security requirements when using HTTPS http://livedocs.adobe.com/flex/2/langref/flash/system/Security.html#allowDomain() not sure if that also applies to AIR.
Comment by Alastair — October 24, 2007 @ 9:16 am
doh that link got cut off the HTML anchor should include the parenthesis after ‘allowDomain’ http://livedocs.adobe.com/flex/2/langref/flash/system/Security.html#allowDomain()
Comment by Alastair — October 24, 2007 @ 9:19 am
Ruby is the programming language under which the Ruby on Rails framework runs. Merb is not a Ruby on Rails gem but a Ruby gem. Merb is a MVC web framework similar to Rails. Please do not confuse the two, Ruby is the language, Rails is the framework.
Comment by Michael Guterl — December 15, 2007 @ 1:58 pm
Thank you fricking captain of the programming police.
Comment by Alastair — December 16, 2007 @ 10:37 am
Hi,
I’m having a little trouble when importing the ‘In a hurry’ version into Flex as an Existing Project.
I instantly receive these errors having made no changes to the code:
1119: Access of possibly undefined property transferable through a reference with static type flash.events:NativeDragEvent.
1120: Access of undefined property DragActions.
1120: Access of undefined property DragManager.
1120: Access of undefined property DragManager.
1120: Access of undefined property TransferableFormats.
I feel as though I am missing something very simple here, any help would be greatly appreciated!
D.Kumar
Comment by Dipen Kumar — January 4, 2008 @ 8:46 am
Hey,
It looks like the Flex Drag classes have changed in Flex Beta 3 (this was made with Beta 2), Merb has also changed since this post, such is the life of living on the egde!
I’ve posted a fix here http://actionsnip.com/snippets/vixiom/merb-on-air-fix-for-flex-beta-3
BTW your the first to see actionsnip.com as I just released it yesterday :)
- Alastair
Comment by Alastair — January 4, 2008 @ 10:48 am
Hi Alastair,
Thank you for the swift response, my Flex project with the drag and drop feature now works very nicely :)
However… the problem I have now is that MERB is not allowing me to perform a db:migrate. I’ve checked the methods inside the MERB app and the db:migrate method does not exist. I have tried various things to run db:migrate but have not been successful.
Again, any help would be greatly appreciated. This is the last step that is needed to complete the project for me.
Oh, also, I’m impressed with your website, looks like a useful resource for me.
D.Kumar
Comment by Dipen Kumar — January 8, 2008 @ 2:30 am
Okay, last one I promise!
Here we go…I figured out why the rake db:migrate was not working. The reason was because I had forgotten about the configuring of a database with MERB as MERB does not come with database support. Anyway, MERB connects fine with the database but the rake db:migrate does not work because it cannot find the schema.rb file even though it exists in dist/schema/schema.rb.
Thoughts, suggestions, plain old pointing out the obvious would help me so much,
D.Kumar
Comment by Dipen Kumar — January 8, 2008 @ 7:31 am
Hey, does this solution work with Files bigger than 100MB?
Thanks,
Marcel
Comment by Marcel Fahle — January 28, 2008 @ 4:37 am
Hi Marcel,
I’m not sure if this applies to AIR apps but I know Flash file upload only handles files less than 100mb.
Comment by Alastair — January 28, 2008 @ 8:50 am
could u send code for upload videos files in flex and send its data to rails ?
Comment by abhishek — January 28, 2008 @ 11:34 pm
[…] and Drop Multiple File UploadHere is the tutorials about Drag and Drop Multiple File Upload.It’s actually using Flex 3 and Adobe AIR.The server side is using the Ruby on Rails gem Merb to […]
Pingback by The list of mine top 3 Flex File Upload Component - Ntt.cc — February 2, 2008 @ 4:47 pm
[…] Merb on AIR - Drag and Drop Multiple File Upload - A slightly old (June 2007) tutorial demonstrating how to use Merb alongside an Adobe AIR powered client to handle file uploads. […]
Pingback by 21 Merb Links, Tutorials and Other Resources — February 4, 2008 @ 8:20 pm
[…] http://blog.vixiom.com/2007/06/29/merb-on-air-drag-and-drop-multiple-file-upload/ […]
Pingback by Philip Arkcoll » Flex AIR Drop Box Prototype — April 1, 2008 @ 1:49 pm
[…] And raw byte access is enabling everything from image and video encoding, to email clients to ftp clients, just weeks after AIR is launched. And heck, I nearly forgot about the online / offline […]
Pingback by Adobe AIR is… | Psyked — April 13, 2008 @ 3:02 am
hi
how can i intregate the air aplication with php to upload files to a ftp server
Comment by Nuno — April 22, 2008 @ 3:39 am
Hello,
Thank you very much for posting the code for this app. Would it be tough to modify this air-application to be a regular flex application? Thanks.
Comment by archie — April 25, 2008 @ 8:30 am
[…] Drag and Drop Flex File Upload with Ruby on Rails […]
Pingback by 9 Flex File Upload Examples Visited — May 8, 2008 @ 6:05 am
[…] and Drop Multiple File Upload Here is the tutorials about Drag and Drop Multiple File Upload.It’s actually using Flex 3 and Adobe AIR.The server side is using the Ruby on Rails gem Merb to […]
Pingback by Top 3 Flex File Upload Components | Flex Tech — June 9, 2008 @ 10:38 am