Rails 使用 Swfupload 无刷新多文件上传的 Session 问题解决
    
  
  Swfupload 是一个 Javascript + Flash 实现的无刷新上传组件,它支持一次选择多个文件上传、上传状态、进度等实用功能。
在 Ruby on Rails 里面使用 Swfupload 来实现多文件上传基本上很简单,按照 Demo 这个页面的例子代码,并修改制定的参数就好了。
但是,如果你的上传需要验证用户登录,那就会有问题出现了。
因为 Swfupload 上传是在 Flash 里面实现的,也就是说 Swfupload 和页面的 Cookie 将会是两个,Session 当然也是同样的。
要避免这个问题,就需要强制的改写 Cookie。
步骤
- 在 Rails 项目里面创建 app/middlewares目录
- 创建 app/middlewares/flash_session_cookie_middleware.rb文件,并存入这段代码:
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 | require 'rack/utils'
class FlashSessionCookieMiddleware
  def initialize(app, session_key = '_session_id')
    @app = app
    @session_key = session_key
  end
  def call(env)
    if env['HTTP_USER_AGENT'] =~ /^(Adobe|Shockwave) Flash/
      params = ::Rack::Utils.parse_query(env['QUERY_STRING'])
      env['HTTP_COOKIE'] = [ @session_key, params[@session_key] ].join('=').freeze unless params[@session_key].nil?
    end
    @app.call(env)
  end
end
 | 
- 修改 config/initializers/session_store.rb并加入:
| 1
2
3
 | # config/initializers/session_store.rb 
ActionController::Dispatcher.middleware.insert_before(ActionController::Base.session_store,
    FlashSessionCookieMiddleware, ActionController::Base.session_options[:key])
 | 
- 修改 config/environment.rb将app/middlewares目录加入到config.load_paths里面:
| 1
2
3
4
5
6
 | # config/environment.rb
Rails::Initializer.run do |config|
  # ..... 省略其他的一些代码
  config.load_paths += %W( #{RAILS_ROOT}/app/middlewares )
  # ..... 省略其他的一些代码
end
 | 
- 对 脚本的 upload_url 进行修改,加入 session 参数:
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 | <!-- 如原始的代码是这样 -->
<script type="text/javascript">
  var swfu;
  window.onload = function () {
    swfu = new SWFUpload({
      upload_url: '<%= link_to :controller => "photos", :action => "create" %>',
      //....... 省略后面的...
  }
</script>
<!-- 修改为 -->
<script type="text/javascript">
  var swfu;
  window.onload = function () {
    swfu = new SWFUpload({
      upload_url: '<%= link_to :controller => "photos", :action => "create", ActionController::Base.session_options[:key]
 => cookies[ActionController::Base.session_options[:key]] %>',
      //....... 省略后面的...
  }
</script>
<!--
   这样一来,upload_url 就会从之前的 
  /photos/create 
  变为 
  /photos/create?_projectname_session_key=asdgkljasdklgjasdklgjlakjlwje 
  类似的地址
  _projectname_session_key 是在 config/initializers/session_store.rb 里面配置的 
  ActionController::Base.session 的 :key 的值
-->
 | 
| 1
 | session :cookie_only => false, :only => :create
 | 
参考资料: