Making SWFUpload and Rails 2.1 sessions work together

October 4th, 2008

One of my recent projects required the use of SWFUpload on a Rails 2.1 project. The project involved users uploading multiple photographs, and each photographs must be associated with an authenticated user. The problem is that SWFUpload doesn’t play nice with Rails 2 when it comes to handling sessions.

Here are some of the issues:

  1. Flash doesn’t send the session cookies up to Rails 2. Adam says there is a way around this, so look for that in the next blog post.
  2. Flash won’t send session_id as a hidden tag on a multipart upload.
  3. Rails 2+ has forgery protection keeping session_id from being passed through the query string.

One way around this is to monkey-patch CGI::Session so it forcibly sets session_id from the query string.

These solutions are outdated. Rails 2.1 will detect the presence of the :session_key set in config/environment.rb and throw an error. The solution is a kludge on top of a kludge:

# Add this to config/initaializers/swfupload_session_hack.rb

# Based on the code from http://seventytwo.co.uk/posts/making-swfupload-and-rails-work-together

# The following code is a work-around for the Flash 8 bug that prevents our multiple file uploader
# from sending the _session_id.  Here, we hack the Session#initialize method and force the session_id
# to load from the query string via the request uri. (Tested on Lighttpd, Mongrel, Apache)
class CGI::Session
  alias original_initialize initialize

  def initialize(request, option = {})
    option = scan_for_session_id(request, '_swfupload_session_id', option) unless option['session_id']
    original_initialize(request, option)
  end

  def scan_for_session_id(request, session_key = '_session_id', option = {})
    query_string = if (qs = request.env_table["QUERY_STRING"]) and qs != ""
      qs
    elsif (ru = request.env_table["REQUEST_URI"][0..-1]).include?("?")
      ru[(ru.index("?") + 1)..-1]
    end
    if query_string and query_string.include?(session_key)
      option['session_id'] = query_string.scan(/#{session_key}=(.*?)(&.*?)*$/).flatten.first
    end
    return option
  end
end

Then in the upload view, you have to use:

upload_url: "<%= photographs_path %>?_swfupload_session_id=<%=h session.session_id %>"

Note that you are passing the session key to _swfupload_session_id, and not whatever session key is set in config/environment.rb.

I have tried this with Cookie Store, and it fails to work, at least on Firefox 3. The reason is that session.session_id will return the entire encoded session, including newlines that messes up the Javascript. There are probably ways around this, but considering that I wasn’t going to use Cookie Store when it goes into production, I switched it using to ActiveStore. This is likely to work with memcached session store, but I have not tested that yet.

1 Response to “Making SWFUpload and Rails 2.1 sessions work together”

  1. Kalle Says:
    I'm using ActiveStore also but I got error about authenticity token. Testing in Leopard, Mongrel, Rails 2.1 and FireFox 3 ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken): /Library/Ruby/Gems/1.8/gems/actionpack-2.1.1/lib/action_controller/request_forgery_protection.rb:86:in `verify_authenticity_token'

Sorry, comments are closed for this article.


© Copyright 2008 Isshen Solutions, Inc. All Rights Reserved.