module UploadProgress::ClassMethods
Action Pack Upload Progress
for multipart uploads¶ ↑
The UploadProgress
module aids in the process of viewing an Ajax driven upload status when working with multipart forms. It offers a macro that will prepare an action for handling the cleanup of the Ajax updating including passing the redirect URL and custom parameters to the Javascript finish handler.
UploadProgress
is available for all multipart uploads when the upload_status_for
macro is called in one of your controllers.
The progress is stored as an UploadProgress::Progress
object in the session and is accessible in the controller and view with the upload_progress
method.
For help rendering the UploadProgress
enabled form and supported elements, see ActionView::Helpers::UploadProgressHelper.
Automatic updating on upload actions¶ ↑
class DocumentController < ApplicationController upload_status_for :create def create # ... Your document creation action end end
The upload_status_for
macro will override the rendering of the action passed if upload_id
is found in the query string. This allows for default behavior if Javascript is disabled. If you are tracking the upload progress then create
will now return the cleanup scripts that will terminate the polling of the upload status.
Customized status rendering¶ ↑
class DocumentController < ApplicationController upload_status_for :create, :status => :custom_status def create # ... Your document creation action end def custom_status # ... Override this action to return content to be replaced in # the status container render :inline => "<%= upload_progress.completed_percent rescue 0 %> % complete", :layout => false end
The default status action is upload_status
. The results of this action are added used to replace the contents of the HTML elements defined in upload_status_tag
. Within upload_status
, you can load the Progress
object from the session with the upload_progress
method and display your own results.
Completion of the upload status updating occurs automatically with an after_action
call to finish_upload_status
. Because the upload must be posted into a hidden IFRAME to enable Ajax updates during the upload, finish_upload_status
overwrites the results of any previous render
or redirect_to
so it can render the necessary Javascript that will properly terminate the status updating loop, trigger the completion callback or redirect to the appropriate URL.
Basic Example (View):¶ ↑
<%= form_tag_with_upload_progress({:action => 'create'}, {:finish => 'alert("Document Uploaded")'}) %> <%= upload_status_tag %> <%= file_field 'document', 'file' %> <%= end_form_tag %>
Basic Example (Controller):¶ ↑
class DocumentController < ApplicationController upload_status_for :create def create @document = Document.create(params[:document]) end end
Extended Example (View):¶ ↑
<%= form_tag_with_upload_progress({:action => 'create'}, {}, {:action => :custom_status}) %> <%= upload_status_tag %> <%= file_field 'document', 'file' %> <%= submit_tag "Upload" %> <%= end_form_tag %> <%= form_tag_with_upload_progress({:action => 'add_preview'}, {:finish => 'alert(arguments[0])'}, {:action => :custom_status}) %> <%= upload_status_tag %> <%= submit_tag "Upload" %> <%= file_field 'preview', 'file' %> <%= end_form_tag %>
Extended Example (Controller):¶ ↑
class DocumentController < ApplicationController upload_status_for :add_preview, :create, {:status => :custom_status} def add_preview @document = Document.find(params[:id]) @document.preview = Preview.create(params[:preview]) if @document.save finish_upload_status "'Preview added'" else finish_upload_status "'Preview not added'" end end def create @document = Document.new(params[:document]) upload_progress.message = "Processing document..." session.update @document.save redirect_to :action => 'show', :id => @document.id end def custom_status render :inline => '<%= upload_progress_status %> <div>Updated at <%= Time.now %></div>', :layout => false end
Environment checklist¶ ↑
This is an experimental feature that requires a specific webserver environment. Use the following checklist to confirm that you have an environment that supports upload progress.
Ruby:¶ ↑
-
Running the command `ruby -v` should print “ruby 1.8.2 (2004-12-25)” or older
Web server:¶ ↑
-
Apache 1.3, Apache 2.0 or Lighttpd 1.4 (need to build lighttpd from CVS)
FastCGI bindings:¶ ↑
-
> 0.8.6 and must be the compiled C version of the bindings
-
The command `ruby -e “p require('fcgi.so')”` should print “true”
Apache/Lighttpd FastCGI directives:¶ ↑
-
You must allow more than one FCGI server process to allow concurrent requests.
-
If there is only a single FCGI process you will not get the upload status updates.
-
You can check this by taking a look for running FCGI servers in your process list during a progress upload.
-
Apache directive: FastCGIConfig -minProcesses 2
-
Lighttpd directives taken from config/lighttpd.conf (min-procs):
fastcgi.server = ( ".fcgi" => ( "APP_NAME" => ( "socket" => "/tmp/APP_NAME1.socket", "bin-path" => "Rails.root/public/dispatch.fcgi", "min-procs" => 2 ) ) )
config/environment.rb:¶ ↑
-
Add the following line to your config/environment.rb and restart your web server.
-
ActionController::Base.enable_upload_progress
Development log:¶ ↑
-
When the upload progress is enabled by you will find something the following lines:
-
“Multipart upload with progress (id: 1, size: 85464)”
-
“Finished processing multipart upload in 0.363729s”
-
If you are properly running multiple FCGI processes, then you will see multiple entries for rendering the “upload_status” action before the “Finish processing…” log entry. This is a *good thing* :)
Public Instance Methods
Creates an after_action
which will call finish_upload_status
creating the document that will be loaded into the hidden IFRAME, terminating the status polling forms created with form_with_upload_progress
.
Also defines an action upload_status
or a action name passed as the :status
option. This status action must match the one expected in the form_tag_with_upload_progress
helper.
# File lib/upload_progress/lib/upload_progress.rb, line 184 def upload_status_for(*actions) after_action :finish_upload_status, :only => actions define_method(actions.last.is_a?(Hash) && actions.last[:status] || :upload_status) do render(:inline => '<%= upload_progress_status %>', :layout => false) end end