Vixiom Axioms

March 5, 2008

Interesting Links: YUIRails, Ebb faster than Mongrel and thin

Filed under: Ajax, JavaScript, Merb, Ruby on Rails Alastair @ 7:23 am

The JavaScript library I use most after prototype is YUI so a big thanks to Chetan Patil for making it much easier to use in Rails.

Ruby Inside has a post on Ebb a small and fast web server for hosting Rails and Merb applications (and soon Django).

Ebb is a small, extremely high performance Web / HTTP server designed specifically for hosting applications built upon Web frameworks such as Rails and Merb (and, in future, apps on other non-Ruby frameworks.) The design is event based (similar to that used by Ruby daemons that use EventMachine) but Ebb itself is written in C and dispatches requests to Rack adapters. This is a real leapfrog over the popular Mongrel and Thin daemons which are primarily written in Ruby, and results in scary levels of performance.

Digg! submit Interesting Links: YUIRails, Ebb faster than Mongrel and thin to stumbleupon.com submit Interesting Links: YUIRails, Ebb faster than Mongrel and thin to del.icio.us submit Interesting Links: YUIRails, Ebb faster than Mongrel and thin to reddit.com Like this post? subscribe to the feed.

November 7, 2007

Merbivore

Filed under: Merb, Ruby Alastair @ 3:17 pm

Merb gets a slick new site.

Digg! submit Merbivore to stumbleupon.com submit Merbivore to del.icio.us submit Merbivore to reddit.com Like this post? subscribe to the feed.

June 29, 2007

Merb on AIR - Drag and Drop Multiple File Upload

Filed under: AIR, ActionScript, Flex, Merb, Ruby Alastair @ 12:07 am

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 ‘dist/app/fx‘).

If you haven’t before install Merb

$ sudo gem install merb

Then create a new Merb app

$ merb -g merb_air_upload

and dive on in

$ cd merb_air_upload

We’ll need two folders not in a Merb skeleton, one for Flex, and one for our uploads

$ mkdir dist/app/fx
$ mkdir dist/public/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

$ ./script/new_migration CreateUserFiles

and edit it (dist/schema/migrations/002_create_user_files.rb) to look like so

class CreateUserFiles < ActiveRecord::Migration
  def self.up
    create_table :user_files do |t|
      t.column :filename, :string, :null => false
    end
  end

  def self.down
    drop_table :user_files
  end
end

rake your db

$ rake db:migrate

Then create a UserFile model (dist/app/models/user_file.rb)

class UserFile < ActiveRecord::Base
end

and an upload controller (dist/controllers/upload.rb)

class Upload < Application

  def index
    # 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/#{@upload.id}
      # move
      destination = dist_root + /public/uploads/#{@upload.id}/#{params[:Filename]}
      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:

<?xml version=1.0 encoding=utf-8?>
<app:App
    xmlns:mx=http://www.adobe.com/2006/mxml
    xmlns:app=com.vixiom.merb_air_upload.*
    layout=vertical
    width=300 height=375
    backgroundGradientAlphas=[1.0, 1.0]
    backgroundGradientColors=[#F4F4F4, #E0E0E0]
    paddingBottom=10 paddingLeft=10 paddingRight=10 paddingTop=10
    verticalScrollPolicy=off horizontalScrollPolicy=off>

    <mx:VBox id=“files_vb”
        width=“100%” height=“300″
        backgroundColor=“#FFFFFF”
        horizontalScrollPolicy=“off”
        paddingBottom=“5″ paddingLeft=“5″ paddingRight=“5″ paddingTop=“5″ borderColor=“#ABABAB” borderStyle=“inset”>
    </mx:VBox>

    <mx:Button id=“upload_btn” label=“Upload Files”/>

</app:App>

It’s hooked up to it’s code behind ‘App.as’ class by the xmlns tag (xmlns:app=com.vixiom.merb_air_upload.*) 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 class App extends WindowedApplication
    {
        private var filesToUpload :Array
        private var UploadProgressComponents :Array;
        public var files_vb:VBox;
        public var upload_btn:Button;
        private var uploadURL:URLRequest;

        /*
         * Constructor
         */
        public function App() :void
        {
            addEventListener( FlexEvent.CREATION_COMPLETE, creationCompleteHandler );
        }

        /*
         * creationComplete
         *
         * called when the AIR has finishe loading, sets up drag/drop event listeners reference objects
         *
         */
        private function creationCompleteHandler( event:FlexEvent ) :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 function onDragEnter( event:NativeDragEvent ) :void
        {
           DragManager.acceptDragDrop(this);
        }

        /*
         * onDragDrop
         *
         * when files are dropped…
         */
        private function onDragDrop( event:NativeDragEvent ) :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 function addFile( f:FileReference ) :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 function completeHandler( e:Event ) :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 function ioErrorHandler( event:IOErrorEvent ) :void
        {
            trace(ioErrorHandler:  + event);
        }

        /*
         * upload!
         */
        private function upload( e:MouseEvent ) :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)

<?xml version=1.0 encoding=utf-8?>
<mx:VBox
    xmlns:mx=“http://www.adobe.com/2006/mxml”
    paddingBottom=“5″ paddingLeft=“5″ paddingRight=“5″ paddingTop=“5″
    borderColor=“#BABABA” borderStyle=“solid” borderThickness=“2″
    width=“100%”
    backgroundColor=“#F7F7F7″>

    <mx:Label id=“file_lb” text=“Label” fontWeight=“bold” color=“#000000″/>
    <mx:ProgressBar id=“pb” labelPlacement=“right” label=“” width=“100%”/>

</mx:VBox>

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!

Digg! submit Merb on AIR - Drag and Drop Multiple File Upload to stumbleupon.com submit Merb on AIR - Drag and Drop Multiple File Upload to del.icio.us submit Merb on AIR - Drag and Drop Multiple File Upload to reddit.com Like this post? subscribe to the feed.

June 27, 2007

I heart Merb

Filed under: Flash, Flex, Merb, Ruby Alastair @ 10:53 pm

Yes every new framework sets my heart a flutter, but this time it’s for real.

Developing Flex/Flash on top of Rails? What if you could get ActiveRecord and RESTful routing at almost eight times the speed with 75% less RAM? How about all that and real concurrency, including true multiple file upload? All of the above without the Rails attitude? You need to get you some Merb.

Models look the same:

class Photo < ActiveRecord::Base
  belongs_to :photo_roll
  acts_as_list :scope => :photo_roll

  def to_json
    self.attributes.to_json
  end
end

Controllers look the same:

class PhotoRolls < Application

  def index
    @photo_rolls = PhotoRoll.find(:all)
    render :js => @photo_rolls.to_json
  end

end

Then consume away in Flex…

public function find() : void
        {
            var svc:JSONRESTService = new JSONRESTService();
            svc.url = /photo_rolls
            svc.sendRESTfully( index, null, onResult, onFault );
        }

That’s a custom JSON REST Service which will be showing up in a future tutorial.

or use HAML as a built in templating engine for all your HTML needs.

Merb!
Merb Docs!
Merb Tutorial!

Digg! submit I heart Merb to stumbleupon.com submit I heart Merb to del.icio.us submit I heart Merb to reddit.com Like this post? subscribe to the feed.

Powered by WordPress