Having spent most of Saturday trying to get files to upload from a Flex application to a Rails backend, fighting against both Flex and Rails all the way, I thought I’d collect together some of the things that have helped me work through this in the hope that others don’t have to spend quite as long battling through this. Note however that these are not necessarily best pratices, more a collection of tips that helped me in my situation, there are probably better ways to do some or all of the things that I’ll be writing about - and if you know of any improvements/alternatives I’d love to hear about them.
In my situation I am uploading images to Rails which is using attachment_fu to handle the images and the thumbnail generation. Some of these tips will be relevant to all more generic issues, such as uploading files from Flex, and some will be more specific, such as making attachment_fu work with images uploaded from Flex.
Uploading files with Flex
To upload files with flex you need to use either the FileReference or FileReferenceList classes, the main difference between these two is that FileReference is for uploading single files and FileReferenceList allows multiple file uploads.
Issue 1: How to send other data, such as meta/model data with the file upload:
Say you want to upload an image and save that using Rails along with other model data for that image (such as a title etc.) then you’ll have to hack that into the request that FileReference sends.
This Adobe tech note recommends using the
uploadDataFieldName argument of the
upload() method, however to me this seems like a really awful hack as you’ll then have to parse the name/value pair string in your
uploadDataFieldName param at the backend. What you really want is separate parameters (ideally within the POST body).
The only viable solution I could come across was using the query string to pass the parameters through, your mileage may vary on this depending on the parameters you are sending, but I’m pretty sure that no modern browsers enforce the 255 character limit on a URL anymore.
Issue 2: Session cookie not sent in Firefox:
This problem is explained really well over at Thanks Mister!, it may apply to other browsers (probably the other gecko-based browsers work the same) but quite simply it means that if you’re relying on some data in your session during the upload you need to manually pass the session cookie through, however this raises further issues with Rails, so I’ll break it down further.
Issue 2: Part 1 – Passing the cookie when uploading files with FileReference:
It’s fairly simple to get around this part of the problem, you just need to include your session identifier within the query string, the biggest issue with this is getting the cookie value – as Flash doesn’t have native access to the browsers cookies.
Issue 2: Part 2 – Rails won’t let you pass session ids in the query string:
So now we need to tweak Rails to let us pass the session id via the query string, luckily there is another great post on this, however some of the Rails 2 security improvements require further workarounds which are in the comments on that post.
To quickly cover what you need to do is as follows:
- Add the patch (make sure you get the one for Mongrel/Apache linked at the bottom of the post) to the
CGI::Sessionclass to your application – it really deserves to live in a plugin rather than the environment.rb file, which you’ll have to roll yourself.
- For Rails 2 you have to add another override by adding
session :cookie_only => falseat the controller level. I personally feel it is best to do this in just the controller that you’re using to upload the files with.
- I still had issues with it not picking up my session – I was using the Rails 2 default of saving the session information in the cookie. There is probably another hack or change that I could make to get around this, but I chose to move (back to) Active Record sessions but this time using the Fast Sessions plugin for a bit of a performance boost.
I’ll probably look into this again at a later date, but right now I just wanted to get this part working and move on.
So now we’ve got our file uploading to the backend, within our session and our other model/meta data being sent as well. “Great we’re done, what else could go wrong now?” is just the kind of thought you’d be forgiven for having. Of course there was another issue that came up which needed to be handled.
Issue 3: Attachment_fu and Flex file uploads
FileReference uploads all files with the MIME type of
application/octet-stream which gives us a couple of problems:
- Your attachment_fu
content-typefilter will probably reject all uploads out of hand - the easy hack would seem to be to add in the
application/octet-streamto your acceptable content-types, but that’s an awful hack that basically removes the content-type filtering and doesn’t address our second issue.
- If using attachment_fu to create thumbnails and you do accept the
application/octet-streamMIME then you won’t have any thumbnails generated, because as far as attachment_fu is concerned your upload is not an image.
Again the solution was only a few searches away, and the changes covered in this post over at Vixiom Axioms do fix the issue – although note that I had issues with that fix and had to apply my own changes - see the comment on that post.
So finally we have file uploads working from Flex to Rails, our session information is maintained, we’re passing along our model data and our images are being handled as they are supposed to.
This really shouldn’t have been this difficult, it should have been a simple case of using FileReference add some data to be POSTed and we’d be done but alas decisions made in/or issues with the Flash player lead to this merry dance of hacks, tweaks and workarounds to make everything sing to the same hymn-sheet.
Hopefully covering this and collecting together these links will save someone else from a wasted day of figuring out the solution to the myriad of problems that I encountered.