Uploadify is a great project to provide file uploads in your project. The problem is, it’s written in flash.
Besides the point that it is flash, there’s something else that has been bothering me a lot: sessions. ~ The problem is like this. When a browsers opens a connection to your Rails app, it has a session. Normally, session information is stored a cookie that is sent with every request. This session also contains information needed for you to stay logged in as a particular user.
If you embed Flash on your site and have it communicate with your Rails application, it will start a new session. Basically, Flash just acts as a whole other browser.
Because of this behaviour, when a logged in user uploads files with Uploadify, the uploads will appear to come from an unauthenticated user. There is no session information provided by flash to identify that a user is signed in.
The old solution
The old solution I’ve found around the web is to work around this session problem by forcing flash to send the browser’s session information. This solution also requires you to add a piece of rack middleware to your app that takes any requests from a flash client and hacks the session to look like it came from the browser.
Besides the fact that I couldn’t get this hack to work, it still is a big hack. So, what to do?
A word on devise
I happen to use Devise in my app to authenticate users. As you may know, Devise is very complete. It includes everything ranging from sign up, forgotten passwords and even account locking. It also features token authentication.
Token authentication means that a user can authenticate himself by providing a unique token, in most cases a string of random characters.
A common use case for this token authentication is to provide users with a secret link to an RSS feed, or to allow quick access to the application from link sent in an email. You click the link and you’re automagically logged in.
The new solution
So, this token authentication got me thinking. Instead of sending an encoded string with session information to flash, which in turn sends it to the server, which in turn hacks it into an actual session, I could just send the user’s authentication token along! No sever-side hacks required - it’s all built in into devise already!
Let me show you. First check that your (devise-powered) user has an authentitication token:
@user.authentication_token
=> "4R2bzzQRdoT_iz-ND4Bb"
In case your authentication_token
is nil, you should generate one with
@user.reset_authentication_token!
The next step is to tell Flash to use this authentication token in its request to the server (while uploading files). Nothing fancy here either. Not that this is a snippet from JavaScript, embedded in a HAML template:
$('#image_file').uploadify({
// I omitted all other config options, since they're not relevant.
'script' : '#{images_path(:auth_token => current_user.authentication_token, :format => :json)}'
)
Rails will generate a URL like this:
/images.json?auth_token=4R2bzzQRdoT_iz-ND4Bb
.
The final step is to protect your ImagesController#create
action with
devise.
class ImagesController < ApplicationController
before_filter :authenticate_user!
def create
# Handle your upload
end
end
That’s all. You dont’ even need to add rack middleware or hack Uploadify to allow an authenticated devise user to upload images through flash.
Easy, huh?