Ruby on Rails Web File Download Indicator
Objective: To show how to implement the file download indicator for various Ruby on Rails configurations:
I will divide the article series into three parts.
mongrel
mongrel (s) + nginx
mod_rails
The following is verified with:
The article is based on a link to which is at the very end. But repeating it on my new rails and mnogrels nothing happened. I changed it a little.
Frame Building: Adding Routes:
The preparation phase is completed. Now we need to explain a little how the file upload indicator functions. The form submission should go to the iframe, and using the ajax request from the page itself, you can use the right frequency to contact a certain controller that will return the current state (you can use json, you can use html, here it is done by javascript), and depending on them, on the page move the indicator.
So, there is only one controller, and there are three methods in it: index to display the form for uploading, upload - processing the downloaded file, progress - to obtain data on the download status. The controller is as follows:
skip_before_filter is needed since requests will go without a token. @upid is a unique identifier.
Now you need to write some kind of plugin for mongrel, which will intercept the file upload (more specifically, access to a specific url) and store data about the download status, in addition, you need to access this data somehow. It’s good that this has already been implemented and the code can be taken from svn:
I suggest doing this as follows: create the lib / progress_plugin.rb file with the following contents:
After that, create a config for mongrel (essentially a regular ruby-file) that will connect this plugin to mongrel: Put in mongrel_upload_progress.conf the following:
path_info is a route that will be intercepted by the plugin to monitor the loading status.
The download form and all the necessary js-nicknames can be taken here .
It remains to simply run the mongrel with the configuration file: The indicator in the browser will look something like this: If you can use drb several mongrel, the details are described in the link below. I did not make any cosmetic changes in the framework of this article. In a more beautiful form, the indicator can be viewed on rghost.ru. Of course, it is a pity to admit that all this was written most likely in vain, since few people manage with a simple mingrel. Usually they put nginx in front of the mongrel or generally replace it with apache with mod_passenger. I plan to write articles about them later.
mongrel upload progress
I will divide the article series into three parts.
mongrel
mongrel (s) + nginx
mod_rails
The following is verified with:
Ruby on Rails 2.2.2
ruby 1.8.6 (2008-03-03 patchlevel 114) [universal-darwin9.0]
mongrel 1.1.5
Mac OS X 10.5.6
Part I. How to do this with mongrel
The article is based on a link to which is at the very end. But repeating it on my new rails and mnogrels nothing happened. I changed it a little.
Frame Building: Adding Routes:
rails upload
cd upload
rm public/index.html
script/generate controller home index upload progress
touch app/views/layouts/application.html.erb
Copy Source | Copy HTML- ActionController::Routing::Routes.draw do |map|
- map.root :controller => 'home'
- map.upload '/upload', :controller => 'home', :action => 'upload'
- map.progress '/progress', :controller => 'home', :action => 'progress'
- end
-
The preparation phase is completed. Now we need to explain a little how the file upload indicator functions. The form submission should go to the iframe, and using the ajax request from the page itself, you can use the right frequency to contact a certain controller that will return the current state (you can use json, you can use html, here it is done by javascript), and depending on them, on the page move the indicator.
So, there is only one controller, and there are three methods in it: index to display the form for uploading, upload - processing the downloaded file, progress - to obtain data on the download status. The controller is as follows:
Copy Source | Copy HTML- class HomeController < ApplicationController
- skip_before_filter :verify_authenticity_token, :only => [:progress]
-
- def index
- @upid = Time.now.tv_sec.to_s
- end
-
- def upload
- render :text => 'done'
- end
-
- def progress
- @status = Mongrel::Uploads.check(params[:upload_id])
- respond_to do |format|
- format.js
- end
- end
- end
skip_before_filter is needed since requests will go without a token. @upid is a unique identifier.
Now you need to write some kind of plugin for mongrel, which will intercept the file upload (more specifically, access to a specific url) and store data about the download status, in addition, you need to access this data somehow. It’s good that this has already been implemented and the code can be taken from svn:
svn co svn://rubyforge.org/var/svn/mongrel/trunk/projects/mongrel_upload_progress
I suggest doing this as follows: create the lib / progress_plugin.rb file with the following contents:
Copy Source | Copy HTML- class Upload < GemPlugin::Plugin "/handlers"
- include Mongrel::HttpHandlerPlugin
-
- def initialize(options = {})
- @path_info = Array(options[:path_info])
- @frequency = options[:frequency] || 3
- @request_notify = true
- if options[:drb]
- require 'drb'
- DRb.start_service
- Mongrel.const_set :Uploads, DRbObject.new(nil, options[:drb])
- else
- Mongrel.const_set :Uploads, Mongrel::UploadProgress.new
- end
- Mongrel::Uploads.debug = true if options[:debug]
- end
-
- def request_begins(params)
- upload_notify(:add, params, params[Mongrel::Const::CONTENT_LENGTH].to_i)
- end
-
- def request_progress(params, clen, total)
- upload_notify(:mark, params, clen)
- end
-
- def process(request, response)
- upload_notify(:finish, request.params)
- end
-
- private
- def upload_notify(action, params, *args)
- return unless @path_info.include?(params['PATH_INFO']) &&
- params[Mongrel::Const::REQUEST_METHOD] == 'POST' &&
- upload_id = Mongrel::HttpRequest.query_parse(params['QUERY_STRING'])['upload_id']
- if action == :mark
- last_checked_time = Mongrel::Uploads.last_checked(upload_id)
- return unless last_checked_time && Time.now - last_checked_time > @frequency
- end
- Mongrel::Uploads.send(action, upload_id, *args)
- Mongrel::Uploads.update_checked_time(upload_id) unless action == :finish
- end
- end
-
- # Keeps track of the status of all currently processing uploads
- class Mongrel::UploadProgress
- attr_accessor :debug
- def initialize
- @guard = Mutex.new
- @counters = {}
- end
-
- def check(upid)
- @counters[upid].last rescue nil
- end
-
- def last_checked(upid)
- @counters[upid].first rescue nil
- end
-
- def update_checked_time(upid)
- @guard.synchronize { @counters[upid][0] = Time.now }
- end
-
- def add(upid, size)
- @guard.synchronize do
- @counters[upid] = [Time.now, {:size => size, :received => 0}]
- puts "#{upid}: Added" if @debug
- end
- end
-
- def mark(upid, len)
- return unless status = check(upid)
- puts "#{upid}: Marking" if @debug
- @guard.synchronize { status[:received] = status[:size] - len }
- end
-
- def finish(upid)
- @guard.synchronize do
- puts "#{upid}: Finished" if @debug
- @counters.delete(upid)
- end
- end
-
- def list
- @counters.keys.sort
- end
- end
-
After that, create a config for mongrel (essentially a regular ruby-file) that will connect this plugin to mongrel: Put in mongrel_upload_progress.conf the following:
touch config/mongrel_upload_progress.conf
Copy Source | Copy HTML- require 'progress_plugin'
- uri "/", :handler => plugin('/handlers/upload', :path_info => '/upload'), :in_front => true
-
path_info is a route that will be intercepted by the plugin to monitor the loading status.
The download form and all the necessary js-nicknames can be taken here .
It remains to simply run the mongrel with the configuration file: The indicator in the browser will look something like this: If you can use drb several mongrel, the details are described in the link below. I did not make any cosmetic changes in the framework of this article. In a more beautiful form, the indicator can be viewed on rghost.ru. Of course, it is a pity to admit that all this was written most likely in vain, since few people manage with a simple mingrel. Usually they put nginx in front of the mongrel or generally replace it with apache with mod_passenger. I plan to write articles about them later.
mongrel_rails start -S config/mongrel_upload_progress.conf
List of references
mongrel upload progress