开发者

uploading two files in one POST request to rails server

I have a flex app that wants to upload two images to a rails server in the same POST request. I think I'm creating the data part of the POST request okay, but I'm not sure. When I print the params that came in on the rails side, I only see one file.

public class MultipartDataHandler extends EventDispatcher
{
    //<net:URLLoader id="loader" complete="completeHandler(event)" dataFormat="binary"  />
    private var loaderContext:LoaderContext = new LoaderContext(true);
    private var loader:URLLoader = new URLLoader();

    public function MultipartDataHandler()
    {
    }

    public function sendToServer(exteriorBitmapData:BitmapData, interiorBitmapData:BitmapData):void {
        var xml_file:String = UserPreference.getInstance().toXML().toXMLString(); 
        var gongos_id:int =开发者_如何转开发 UserPreference.getInstance().gongosId;
        var room_id:int = UserPreference.getInstance().roomId;
        var car_id:int = UserPreference.getInstance().theCar.id;

        // 1. Encode image as a png

        //          var bitmap:Bitmap = image.content as Bitmap;
        //          var bytes:ByteArray = pngEncoder.encode(bitmap.bitmapData);

        var pngEncoder:PNGEncoder = new PNGEncoder();
        var exteriorBytes:ByteArray = pngEncoder.encode(exteriorBitmapData);
        var interiorBytes:ByteArray = pngEncoder.encode(interiorBitmapData);

        // 2. Create multip part request
        var boundary:String = '------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7';
        var url:String = UserPreference.urlize("/cars/upload.xml");
        var request: URLRequest = new URLRequest(url);
        request.data = getMultiPartRequestData(boundary, 'car', exteriorBytes, interiorBytes, xml_file, gongos_id, room_id, car_id);
        request.method = URLRequestMethod.POST;
        request.contentType = "multipart/form-data; boundary=" + boundary; 

        // 3. Send to Server
        loader.load(request);
        loader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
        loader.addEventListener(Event.COMPLETE, loaderCompleteHandler);

    }

    private function getMultiPartRequestData(boundary:String, resourceName:String, 
                                             exteriorBytes:ByteArray, 
                                             interiorBytes:ByteArray,
                                             xml_file:String, 
                                             gongos_id:int, room_id:int, car_id:int):ByteArray {
        var lf:String = "\r\n";
        var part1:String =  '--' + boundary + lf + 
            'Content-Disposition: form-data; name="Filename"' + lf + lf +
            '{0}' + lf +
            '--' + boundary + lf +
            'Content-Disposition: form-data; name="{1}[xml]"' + lf + lf +  
            '{2}' + lf + 
            '--' + boundary + lf + 
            'Content-Disposition: form-data; name="gongos_id"' + lf + lf +  
            '{3}' + lf + 
            '--' + boundary + lf + 
            'Content-Disposition: form-data; name="room_id"' + lf + lf +  
            '{4}' + lf + 
            '--' + boundary + lf + 
            'Content-Disposition: form-data; name="car_id"' + lf + lf +  
            '{5}' + 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="{1}[interior_photo]"; ' +
            'filename="{0}"' + lf +
            'Content-Type: application/octet-stream' + lf +lf;
        var part3:String =  '--' + boundary + lf +
            'Content-Disposition: form-data; name="Upload"' + lf + lf +
            'Submit Query' + lf +
            '--' + boundary +  '--';

        part1 = StringUtil.substitute(part1, 'car.png', resourceName, 
            xml_file, gongos_id, room_id, car_id);
        part2 = StringUtil.substitute(part2, 'interior.png', resourceName);


        var result:ByteArray = new ByteArray();
        result.writeMultiByte(part1, "ascii");
        result.writeBytes(exteriorBytes, 0, exteriorBytes.length)
        result.writeMultiByte(part2, "ascii");
        result.writeBytes(interiorBytes, 0, interiorBytes.length)
        result.writeMultiByte(part3, "ascii");

        trace(part1 + "EXTERIOR BYTES" + part2 + "INTERIOR BYTES" + part3);
        return result;
    }

}

}

This is what the debug console prints. Note that I'm not printing the actual bytes in the console as that would be really painful, but you can see where they go.

--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="Filename"

car.png
--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="car[xml]"

<creation>
  <car>
    <bodyId>1</bodyId>
    <themeId>0</themeId>
    <roomId>0</roomId>
    <userId>0</userId>
    <name>null</name>
    <exterior/>
    <interior/>
  </car>
</creation>
--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="gongos_id"

0
--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="room_id"

1
--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="car_id"

0
--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="car[photo]"; filename="car.png"
Content-Type: application/octet-stream

EXTERIOR BYTES--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="car[interior_photo]"; filename="interior.png"
Content-Type: application/octet-stream

INTERIOR BYTES--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="Upload"

Submit Query
--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7--

And then lastly, here is what Rails says.

--- !map:HashWithIndifferentAccess 
room_id: "1"
Filename: car.png
format: xml
action: upload
car_id: "0"
controller: cars
car: !map:HashWithIndifferentAccess 
  photo: !ruby/object:File {}

  xml: |-
    <creation>
      <car>
        <bodyId>1</bodyId>
        <themeId>0</themeId>
        <roomId>0</roomId>
        <userId>0</userId>
        <name>null</name>
        <exterior/>
        <interior/>
      </car>
    </creation>
gongos_id: "0"
Processing CarsController#upload to xml (for 127.0.0.1 at 2011-03-17 08:05:00) [POST]
  Parameters: {"Filename"=>"car.png", "room_id"=>"1", "car_id"=>"0", "car"=>{"photo"=>#<File:/var/folders/f6/f6zP-E52HiaycvHwz90OtE+++TI/-Tmp-/RackMultipart20110317-24400-14hcvab-0>, "xml"=>"<creation>\n  <car>\n    <bodyId>1</bodyId>\n    <themeId>0</themeId>\n    <roomId>0</roomId>\n    <userId>0</userId>\n    <name>null</name>\n    <exterior/>\n    <interior/>\n  </car>\n</creation>"}, "gongos_id"=>"0"}
[paperclip] identify '-format' '%wx%h' '/var/folders/f6/f6zP-E52HiaycvHwz90OtE+++TI/-Tmp-/stream,24400,0.png[0]' 2>/dev/null
[paperclip] convert '/var/folders/f6/f6zP-E52HiaycvHwz90OtE+++TI/-Tmp-/stream,24400,0.png[0]' '-resize' '500x500>' '/var/folders/f6/f6zP-E52HiaycvHwz90OtE+++TI/-Tmp-/stream,24400,0,24400,0' 2>/dev/null
[paperclip] identify '-format' '%wx%h' '/var/folders/f6/f6zP-E52HiaycvHwz90OtE+++TI/-Tmp-/stream,24400,0.png[0]' 2>/dev/null
[paperclip] convert '/var/folders/f6/f6zP-E52HiaycvHwz90OtE+++TI/-Tmp-/stream,24400,0.png[0]' '-resize' '250x250>' '/var/folders/f6/f6zP-E52HiaycvHwz90OtE+++TI/-Tmp-/stream,24400,0,24400,1' 2>/dev/null
  User Load (0.3ms)   SELECT * FROM "users" WHERE ("users"."gongos_id" = '0' AND "users"."room_id" = '1') LIMIT 1
  Car Create (81.1ms)   INSERT INTO "cars" ("name", "interior_photo_file_name", "room_id", "photo_file_size", "interior_photo_file_size", "interior_photo_updated_at", "created_at", "xml", "photo_file_name", "updated_at", "body_id", "photo_content_type", "deleted", "user_id", "interior_view_id", "theme_id", "photo_updated_at", "parent_car_id", "interior_photo_content_type") VALUES('Faxo', NULL, NULL, 102547, NULL, NULL, '2011-03-17 12:05:03', '<creation>
 <car>
 <bodyId>1</bodyId>
 <themeId>0</themeId>
 <roomId>0</roomId>
 <userId>0</userId>
 <name>null</name>
 <exterior/>
 <interior/>
 </car>
</creation>', 'car.png', '2011-03-17 12:05:03', 1, 'application/octet-stream', NULL, NULL, NULL, 0, '2011-03-17 12:05:01', NULL, NULL)
[paperclip] Saving attachments.
[paperclip] saving /Users/glurban/code/amfdreamcar/public/system/photos/18/medium/car.png
[paperclip] saving /Users/glurban/code/amfdreamcar/public/system/photos/18/original/car.png
[paperclip] saving /Users/glurban/code/amfdreamcar/public/system/photos/18/thumb/car.png
[paperclip] Saving attachments.
Rendering cars/upload
Completed in 2750ms (View: 60, DB: 81) | 200 OK [http://localhost/cars/upload.xml]

So, as you can see, only one photo (the first one) seems to appear in the params. Switching the order makes only interior_photo appear. What am I doing wrong?

I also tried making two separate calls chained together, but that failed due to Flash 10's security restriction that prevents file upload without the user making an action such as clicking a button. I even tried putting both of the calls to loader.load() in the same function, using a random number generator to create an id on the flex side (because rails needs to know that the two calls are for the same car, and without chaining I can't use the response from the first call to pass back the car id), but I ran into a race condition where the second call somehow got to the server before the first one. Adobe security... FFFFFFFUUUUUU.


Oh god.

Spent like 3 hours on this problem (debugging, trying other failed solutions, etc.).

Then, right after I post this, I realize the problem: line breaks will be the death of me. Add a lf to the front of part2 and part3 and we're good.

:O

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜