Confounding URL typists since 2007.
If you’re using Uploadify, the nifty jQuery file upload plugin — which we’ll forgive for providing all its examples in PHP (*shudder*) — there’s a good chance you followed the general pattern outlined by John Nunemaker over at RailsTips. His article describes in detail how to get Flash to play nicely with Rails sessions using Rack middleware. Unfortunately, Rails 3 requires a few minor changes to this setup.
First up, as before, you’ll need to tell Uploadify about the name of your application’s session key. The important change here is where the session key name can now be found: Rails.application.config.session_options[:key].
<% session_key_name = Rails.application.config.session_options[:key] %>
$('#<%= "#{asset_name}_upload" %>').uploadify({
uploader : '/uploadify/uploadify.swf',
script : '<%= url_for %>',
fileDataName : 'project[<%= "#{asset_name}_attributes" %>][data]',
cancelImg : '/uploadify/cancel.png',
fileDesc : 'Photo or Video',
fileExt : '*.mov;*.mp4;*.avi;*.wmv;*.png;*.jpg;*.gif',
auto : true,
sizeLimit : <%= 100.megabytes %>,
width : 150,
height : 25,
hideButton : true,
wmode : 'transparent',
buttonText : 'Upload',
onComplete : function(a, b, c, response){ eval(response); $('#<%= "#{asset_name}_queue" %>').html(''); },
queueID : 'noQueueForMePlease',
onProgress : function(event, queueID, fileObj, data){ $('#<%= "#{asset_name}_queue" %>').html(data.percentage + '%') },
scriptData : {
'_http_accept': 'application/javascript',
'_method': 'put',
'<%= session_key_name %>' : encodeURIComponent('<%= u cookies[session_key_name] %>'),
'authenticity_token': encodeURIComponent('<%= u form_authenticity_token %>')
}
});
The preceding snippet was taken from an actual application which is a work-in-progress. This application has several file upload “slots” that are handled by accepts_nested_attributes_for on my Project model, and because the request is always an “update” of the parent Project model, it’s safe for me to hard-code the _method as put. That may not be the case for you. You will want to examine the following parameters from this example and change them as needed for your application’s requirements:
Now, you can see we’re passing the session key and form authenticity token in the above code. The trick is that the session key is stored in a cookie, and Flash doesn’t know about it. Enter a slightly modified version of John’s FlashSessionMiddleware.
app/middleware/flash_session_cookie_middleware.rb:
require 'rack/utils'
class FlashSessionCookieMiddleware
def initialize(app, session_key = '_session_id')
= app
= session_key
end
def call(env)
if env['HTTP_USER_AGENT'] =~ /^(Adobe|Shockwave) Flash/
req = Rack::Request.new(env)
env['HTTP_COOKIE'] = [ ,
req.params[] ]
.join('=').freeze unless req.params[].nil?
env['HTTP_ACCEPT'] = "#{req.params['_http_accept']}"
.freeze unless req.params['_http_accept'].nil?
end
.call(env)
end
end
Note that aside from setting the HTTP_COOKIE header to include the session, we’re also setting the HTTP_ACCEPT header (to allow our Rails app to serve up the .js.erb in a respond_to block). Place this file somewhere handy (I followed his suggestion of app/middleware) and make sure it’s loaded at Rails startup by adding the following to config/application.rb inside the class Application block :
# Add additional load paths for your own custom dirs
%w(observers mailers middleware).each do |dir|
config.autoload_paths << "#{config.root}/app/#{dir}"
end
This was the trickiest part. A lot has changed about the Rails boot process between 2.3 and 3.0. While searching for help on getting this set up, I found a bunch of information, most of it bad, on what would work, from different locations for the code to different code altogether. In the end, as it turns out, you can still place the middleware loading code in config/initializers/session_store.rb, but it’s changed quite a bit from Rails 2.3:
Rails.application.config.middleware.insert_before(
ActionDispatch::Session::CookieStore,
FlashSessionCookieMiddleware,
Rails.application.config.session_options[:key]
)
That’s it! Hope this helps you avoid the hassles I dealt with in getting Uploadify up and running with Rails 3.