views:

81

answers:

1

I'm trying to upload a Dynamically generated file from Flex (PNG image) to Ruby on Rails Server back end using the following code (from Flex on Rails book):

        public function save():void
        {

            var bitmapData:BitmapData = new BitmapData(width, height);
            bitmapData.draw(this);

            var ba:ByteArray = (new PNGEncoder()).encode(bitmapData);
            var fileRef:FileReference = new FileReference();

            //TODO: Remove HardCoding of URL here
            var request : URLRequest = new URLRequest("http://localhost:3000/doodles");
            request.method = URLRequestMethod.POST;
            var boundary : String = "----------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7";
            request.contentType = "multipart/form-data; boundary=" + boundary;
            request.data =getMultiPartRequestData(boundary,'doodle','',ba);

            loader.load(request);               
        }

and getMultiPartRequestData function is:

        private function getMultiPartRequestData(boundary:String,
                                                 resourceName:String,
                                                 filename:String,
                                                 bytes:ByteArray):ByteArray {
            Alert.show("haha");
            var lf:String = "\r\n";

            var part1:String = '--' + boundary + lf + 
                'Content-Disposition: form-data; name="Filename"' + lf + lf +
                '{0}' + lf + 
                '--' + boundary + lf ;
            if (_model.authenticityToken != "") {
                part1 += 'Content-Disposition: form-data; name="authenticity_token";' + lf + lf +
                    '{2}' + lf +
                    '--' + boundary + lf ;                      
            }
            part1 += 'Content-Disposition: form-data; name="{1}[x]";' + lf + lf + 
                     '{3}' + lf +
                     '--' + boundary + lf +
                     'Content-Disposition: form-data; name="{1}[y]";' + lf + lf +
                     '{4}' + lf +
                     '--' + boundary + lf +
                     'Content-Disposition: form-data; name="{1}[width]";' + lf + lf +
                     '{5}' + lf +
                     '--' + boundary + lf +
                     'Content-Disposition: form-data; name="{1}[height]"' + lf + lf + 
                     '{6}' + lf +
                     '--' + boundary + lf +
                     'Content-Disposition: form-data; name="{1}[rotation]"' + lf + lf +
                     '{7}' + lf +
                     '--' + boundary + lf +
                     'Content-Disposition: form-data; name="{1}[day_id]"' + lf + lf +  
                     '{8}' + lf + 
                     '--' + boundary + lf +
                     'Content-Disposition: form-data; name="{1}[privacy]"' + lf + lf +  
                     '{9}' + lf + 
                     '--' + boundary + lf + 
                     'Content-Disposition: form-data; name="{1}[canvas_height]"' + lf + lf +  
                     '{10}' + lf + 
                     '--' + boundary + lf +
                     'Content-Disposition: form-data; name="{1}[canvas_width]"' + lf + lf +  
                     '{11}' + lf + 
                     '--' + boundary + lf +
                     'Content-Disposition: form-data; name="commit"' + lf + lf +  
                     'Create' + lf + 
                     '--' + boundary + lf +                      
                     'Content-Disposition: form-data; name="{1}[photo]";' +  
                     'filename="{0}"' + lf +                         
                     'Content-Type: application/octet-stream' + lf + lf     

            var part2:String = '--' + boundary + lf + 
                               'Content-Disposition: form-data; name="Upload"' + lf + lf +
                               'Submit Query' + lf +
                               '--' + boundary + '--'

            var result:ByteArray = new ByteArray();
            // Filling in the parameters as per comment above
            result.writeMultiByte(StringUtil.substitute(part1, 
                                                        filename,
                                                        resourceName,
                                                        _model.authenticityToken,
                                                        _model.boundMinX,
                                                        _model.boundMinY,
                                                        Constants.DEFAULT_DOODLE_WIDTH,
                                                        Constants.MINIMUM_CANVAS_HEIGHT,
                                                        0,
                                                        _model.current_day.id,
                                                        privacyGroup.selectedValue.toString(),
                                                        FlexGlobals.topLevelApplication.height,
                                                        FlexGlobals.topLevelApplication.width), "ascii");
            result.writeBytes(bytes,0,bytes.length);
            result.writeMultiByte(part2, "ascii");
            return result;
        }

I get the following exception:

TypeError (can't convert nil into String):
  vendor/plugins/paperclip/lib/paperclip/iostream.rb:8:in `extname'
  vendor/plugins/paperclip/lib/paperclip/iostream.rb:8:in `to_tempfile'
  vendor/plugins/paperclip/lib/paperclip/attachment.rb:89:in `assign'
  vendor/plugins/paperclip/lib/paperclip.rb:262:in `block in has_attached_file'
  activerecord (2.3.5) lib/active_record/base.rb:2746:in `block in attributes='
  activerecord (2.3.5) lib/active_record/base.rb:2742:in `each'
  activerecord (2.3.5) lib/active_record/base.rb:2742:in `attributes='
  activerecord (2.3.5) lib/active_record/base.rb:2438:in `initialize'
  app/controllers/doodles_controller.rb:16:in `new'
  app/controllers/doodles_controller.rb:16:in `create'
  actionpack (2.3.5) lib/action_controller/base.rb:1331:in `perform_action'
  actionpack (2.3.5) lib/action_controller/filters.rb:617:in `call_filters'
  actionpack (2.3.5) lib/action_controller/filters.rb:610:in `perform_action_with_filters'
  actionpack (2.3.5) lib/action_controller/benchmarking.rb:68:in `block in perform_action_with_benchmark'
  activesupport (2.3.5) lib/active_support/core_ext/benchmark.rb:17:in `block in ms'
  /Users/tammam56/.rvm/rubies/ruby-1.9.1-p378/lib/ruby/1.9.1/benchmark.rb:309:in `realtime'
  activesupport (2.3.5) lib/active_support/core_ext/benchmark.rb:17:in `ms'
  actionpack (2.3.5) lib/action_controller/benchmarking.rb:68:in `perform_action_with_benchmark'
  actionpack (2.3.5) lib/action_controller/rescue.rb:160:in `perform_action_with_rescue'
  actionpack (2.3.5) lib/action_controller/flash.rb:146:in `perform_action_with_flash'
  vendor/plugins/newrelic_rpm/lib/new_relic/agent/instrumentation/controller_instrumentation.rb:253:in `block in perform_action_with_newrelic_trace'
  vendor/plugins/newrelic_rpm/lib/new_relic/agent/method_tracer.rb:141:in `trace_execution_scoped'
  vendor/plugins/newrelic_rpm/lib/new_relic/agent/instrumentation/controller_instrumentation.rb:246:in `perform_action_with_newrelic_trace'
  actionpack (2.3.5) lib/action_controller/base.rb:532:in `process'
  actionpack (2.3.5) lib/action_controller/filters.rb:606:in `process_with_filters'
  actionpack (2.3.5) lib/action_controller/base.rb:391:in `process'
  actionpack (2.3.5) lib/action_controller/base.rb:386:in `call'
  actionpack (2.3.5) lib/action_controller/routing/route_set.rb:437:in `call'
  actionpack (2.3.5) lib/action_controller/dispatcher.rb:87:in `dispatch'
  actionpack (2.3.5) lib/action_controller/dispatcher.rb:121:in `_call'
  actionpack (2.3.5) lib/action_controller/dispatcher.rb:130:in `block in build_middleware_stack'
  activerecord (2.3.5) lib/active_record/query_cache.rb:29:in `call'
  activerecord (2.3.5) lib/active_record/query_cache.rb:29:in `block in call'
  activerecord (2.3.5) lib/active_record/connection_adapters/abstract/query_cache.rb:34:in `cache'
  activerecord (2.3.5) lib/active_record/query_cache.rb:9:in `cache'
  activerecord (2.3.5) lib/active_record/query_cache.rb:28:in `call'
  activerecord (2.3.5) lib/active_record/connection_adapters/abstract/connection_pool.rb:361:in `call'
  actionpack (2.3.5) lib/action_controller/string_coercion.rb:25:in `call'
  rack (1.0.1) lib/rack/head.rb:9:in `call'
  rack (1.0.1) lib/rack/methodoverride.rb:24:in `call'
  actionpack (2.3.5) lib/action_controller/params_parser.rb:15:in `call'
  actionpack (2.3.5) lib/action_controller/session/cookie_store.rb:93:in `call'
  actionpack (2.3.5) lib/action_controller/failsafe.rb:26:in `call'
  rack (1.0.1) lib/rack/lock.rb:11:in `block in call'
  <internal:prelude>:8:in `synchronize'
  rack (1.0.1) lib/rack/lock.rb:11:in `call'
  actionpack (2.3.5) lib/action_controller/dispatcher.rb:114:in `block in call'
  actionpack (2.3.5) lib/action_controller/reloader.rb:34:in `run'
  actionpack (2.3.5) lib/action_controller/dispatcher.rb:108:in `call'
  rails (2.3.5) lib/rails/rack/static.rb:31:in `call'
  rack (1.0.1) lib/rack/urlmap.rb:46:in `block in call'
  rack (1.0.1) lib/rack/urlmap.rb:40:in `each'
  rack (1.0.1) lib/rack/urlmap.rb:40:in `call'
  rails (2.3.5) lib/rails/rack/log_tailer.rb:17:in `call'
  rack (1.0.1) lib/rack/content_length.rb:13:in `call'
  rack (1.0.1) lib/rack/chunked.rb:15:in `call'
  rack (1.0.1) lib/rack/handler/mongrel.rb:64:in `process'
  mongrel (1.1.5) lib/mongrel.rb:159:in `block in process_client'
  mongrel (1.1.5) lib/mongrel.rb:158:in `each'
  mongrel (1.1.5) lib/mongrel.rb:158:in `process_client'
  mongrel (1.1.5) lib/mongrel.rb:285:in `block (2 levels) in run'

When I look into the request data I get the following:

Processing DoodlesController#create (for 127.0.0.1 at 2010-06-28 22:51:57) [POST]
  Parameters: {"Filename"=>"doodle.png", "authenticity_token"=>"4UoCgzNbH1UccJbqV4P+R1mCuLk54fWTXxkZvVBin+I=", "doodle"=>{"x"=>"0", "y"=>"100", "width"=>"1024", "height"=>"768", "rotation"=>"0", "day_id"=>"16", "privacy"=>"meonly", "canvas_height"=>"1298", "canvas_width"=>"2560", "photo"=>#<File:/var/folders/RH/RHekFGKME9uDJbX4d4DG3E+++TI/-Tmp-/RackMultipart20100628-1685-1v2epqd-0>}, "commit"=>"Create"}

Which is very similar to the HTML request data (if I use HTML page instead of Flex):

Processing DoodlesController#create (for 127.0.0.1 at 2010-06-28 21:55:23) [POST]
  Parameters: {"authenticity_token"=>"4UoCgzNbH1UccJbqV4P+R1mCuLk54fWTXxkZvVBin+I=", "doodle"=>{"privacy"=>"myonly", "day_id"=>"1", "x"=>"10", "y"=>"10", "width"=>"1000", "height"=>"1000", "rotation"=>"0", "canvas_height"=>"1000", "canvas_width"=>"1000", "photo"=>#<File:/var/folders/RH/RHekFGKME9uDJbX4d4DG3E+++TI/-Tmp-/RackMultipart20100628-1685-1gnfm5q-0>}, "commit"=>"Create"}

Which Works!

and if I type (in Mac)

open /var/folders/RH/RHekFGKME9uDJbX4d4DG3E+++TI/-Tmp-/RackMultipart20100628-1685-1v2epqd-0

(for the temp file) It opens the PNG file intended!!

Any suggestions on how I can make this to work?

+1  A: 

After pulling my hair for quite some time. I realized the problem was very silly!

I put a debug code inside the Paperclip pluging (Right where the backtrace is stating error:

vendor/plugins/paperclip/lib/paperclip/iostream.rb:8:in `extname'

and I noticed a line like this

name = respond_to?(:original_filename) ? original_filename : (respond_to?(:path) ? path : "stream")

After printing out some debug variables I realized that original_filename is nil which shouldn't be as it should be the actual file name uploaded to the server which is supposed to be doodle.png according to my code. Just to find out that I forgot one space before 'filename' in the data I was sending. So my code:

'Content-Disposition: form-data; name="{1}[photo]";' +  
                     'filename="{0}"' + lf +                         
                     'Content-Type: application/octet-stream' + lf + lf

is Wrong. This code:

'Content-Disposition: form-data; name="{1}[photo] ";' +  //note extra space added here
                     'filename="{0}"' + lf +                         
                     'Content-Type: application/octet-stream' + lf + lf 

Works. That's it!

Tam