⬆️ ⬇️

File Upload Indicator in Ruby on Rails Web Applications

Task: to show how to implement the file loading indicator for different configurations of Ruby on Rails:

I will divide the series of articles into three parts.

mongrel

mongrel (s) + nginx

mod_rails



The following are 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 it with mongrel



The basis of the article, the link to which is at the very end. But repeating it on my new rails and pollereha nothing happened. I changed her a little bit.



Creation of the frame:

rails upload

cd upload

rm public/index.html

script/generate controller home index upload progress

touch app/views/layouts/application.html.erb



')

Adding Routing:

Copy Source | Copy HTML
  1. ActionController :: Routing :: Routes.draw do | map |
  2. map.root: controller => 'home'
  3. map.upload '/ upload' ,: controller => 'home' ,: action => 'upload'
  4. map.progress '/ progress' ,: controller => 'home' ,: action => 'progress'
  5. end




The preparation phase is complete. Now we need to explain a little how the file upload indicator functions. The form submission should go to the iframe, and from the page itself using ajax requests you can refer to a specific controller that will return the current state (you can in json, you can html, javascript is done here), and depending on them on the page move the indicator.



So, there is one controller, and there are three methods in it: index for outputting the form for upload, upload - processing the uploaded file, progress - for getting data on the status of the upload. The controller looks like this:



Copy Source | Copy HTML
  1. class HomeController <ApplicationController
  2. skip_before_filter: verify_authenticity_token,: only => [: progress ]
  3. def index
  4. @upid = Time .now.tv_sec.to_s
  5. end
  6. def upload
  7. render: text => 'done'
  8. end
  9. def progress
  10. @status = Mongrel :: Uploads.check (params [: upload_id])
  11. respond_to do | format |
  12. format .js
  13. end
  14. end
  15. end




skip_before_filter is required since requests will go without a token. @upid is a unique identifier.

Now you need to write a plugin for Mongrel, which will intercept the download files (or rather, refer to a specific url) and store data on the download status, in addition, you need to somehow access this data. It's good that this is already implemented and the code can be taken from svn:



svn co svn://rubyforge.org/var/svn/mongrel/trunk/projects/mongrel_upload_progress



I propose to do this: create a file lib / progress_plugin.rb with the following contents:

Copy Source | Copy HTML
  1. class Upload <GemPlugin :: Plugin "/ handlers"
  2. include Mongrel :: HttpHandlerPlugin
  3. def initialize (options = {})
  4. @path_info = Array (options [: path_info])
  5. @frequency = options [: frequency] || 3
  6. @request_notify = true
  7. if options [: drb]
  8. require 'drb'
  9. DRb.start_service
  10. Mongrel .const_set: Uploads, DRbObject. new ( nil , options [: drb])
  11. else
  12. Mongrel .const_set: Uploads, Mongrel :: UploadProgress.new
  13. end
  14. Mongrel :: Uploads.debug = true if options [: debug]
  15. end
  16. def request_begins (params)
  17. upload_notify (: add , params, params [ Mongrel :: Const :: CONTENT_LENGTH] .to_i)
  18. end
  19. def request_progress (params, clen, total)
  20. upload_notify (( mark , params, clen)
  21. end
  22. def process (request, response)
  23. upload_notify (: finish , request.params)
  24. end
  25. private
  26. def upload_notify (action, params, * args)
  27. return unless @path_info. include ? (params [ 'PATH_INFO' ]) &&
  28. params [ Mongrel :: Const :: REQUEST_METHOD] == 'POST' &&
  29. upload_id = Mongrel :: HttpRequest.query_parse (params [ 'QUERY_STRING' ]) [ 'upload_id' ]
  30. if action ==: mark
  31. last_checked_time = Mongrel :: Uploads. last_checked (upload_id)
  32. return unless last_checked_time && Time .now - last_checked_time> @frequency
  33. end
  34. Mongrel :: Uploads.send (action, upload_id, * args)
  35. Mongrel :: Uploads. update_checked_time (upload_id) unless action ==: finish
  36. end
  37. end
  38. # Keeps track of the status of all currently processing uploads
  39. class Mongrel :: UploadProgress
  40. attr_accessor: debug
  41. def initialize
  42. @guard = Mutex .new
  43. @counters = {}
  44. end
  45. def check (upid)
  46. @counters [upid] .last rescue nil
  47. end
  48. def last_checked (upid)
  49. @counters [upid] .first rescue nil
  50. end
  51. def update_checked_time (upid)
  52. @ guard.synchronize {@counters [upid] [ 0 ] = Time .now}
  53. end
  54. def add (upid, size)
  55. @ guard.synchronize do
  56. @counters [upid] = [ Time .now, {: size => size,: received => 0 }]
  57. puts "# {upid}: Added" if @debug
  58. end
  59. end
  60. def mark (upid, len)
  61. return unless status = check (upid)
  62. puts "# {upid}: Marking" if @debug
  63. @ guard.synchronize {status [: received] = status [: size] - len}
  64. end
  65. def finish (upid)
  66. @ guard.synchronize do
  67. puts "# {upid}: Finished" if @debug
  68. @counters. delete (upid)
  69. end
  70. end
  71. def list
  72. @ counters.keys.sort
  73. end
  74. end




After that, create a config for mongrel (in fact, a normal ruby-file), which will connect this plugin to mongrel:

touch config/mongrel_upload_progress.conf





Put in mongrel_upload_progress.conf you need the following:

Copy Source | Copy HTML
  1. require 'progress_plugin'
  2. uri "/" ,: handler => plugin ( '/ handlers / upload' ,: path_info => '/ upload' ),: in_front => true




path_info is a route that will be intercepted by the plugin to track the status of the download.

Download form and all the necessary js-nicks can be taken here .



It remains to just run the mongrel with the configuration file:

mongrel_rails start -S config/mongrel_upload_progress.conf





The indicator in the browser will look something like this:



If there are several mongrelians you can use drb, the details are described in the link below.



I did not make any cosmetic changes within 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 is written most likely in vain, since few people are just getting along with a simple mongrel. Usually they put nginx in front of the mongrel or even replace it with apache with mod_passenger. I plan to write articles about them later.



References



mongrel upload progress

Source: https://habr.com/ru/post/53191/



All Articles