devroom.io/content/posts/2011-03-27-rails-3-devise-uploadify-no-flash-session-hacks.md

106 lines
3.6 KiB
Markdown
Raw Normal View History

2015-03-26 11:28:08 +00:00
+++
date = "2011-03-27"
title = "Rails 3 + Devise + Uploadify = No Flash Session Hacks"
tags = ["Rails", "rails3", "devise", "uploadify", "flash"]
slug = "rails-3-devise-uploadify-no-flash-session-hacks"
+++
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:
2017-03-20 15:35:19 +00:00
``` ruby
@user.authentication_token
=> "4R2bzzQRdoT_iz-ND4Bb"
```
2015-03-26 11:28:08 +00:00
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:
2017-03-20 15:35:19 +00:00
``` javascript
$('#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)}'
)
```
2015-03-26 11:28:08 +00:00
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.
2017-03-20 15:35:19 +00:00
``` ruby
class ImagesController < ApplicationController
before_filter :authenticate_user!
2015-03-26 11:28:08 +00:00
2017-03-20 15:35:19 +00:00
def create
# Handle your upload
end
end
```
2015-03-26 11:28:08 +00:00
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?