Hi all, I''m trying to send large files (160MB - 1.5GB) using send_file(), it''s working perfectly except that I can''t figure out how to make the downloads resumable. If a download fails, I have to re-download it from scratch. As I''m dealing with large files I can''t set :stream => false Here is how I call send_file from my controller : send_file(@path, :type => (MIMETYPES[File.extname(@path)] || ''application/octet-stream'')) if File.file?(@path) Any ideas ? Should I use send_data() instead ? Is there any Rails support for my problem or do I have to implement this myself ? Thanks Mike -- Michael BAUDINO EPITA 2007 KameHouse Prod.
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Nov 21, 2005, at 5:06 AM, Michael Baudino wrote:> I''m trying to send large files (160MB - 1.5GB) using send_file(), > it''s working perfectly except that I can''t figure out how to make > the downloads resumable. > If a download fails, I have to re-download it from scratch. > As I''m dealing with large files I can''t set :stream => false > > Here is how I call send_file from my controller : > > send_file(@path, :type => (MIMETYPES[File.extname(@path)] || > ''application/octet-stream'')) if File.file?(@path) > > Any ideas ? > Should I use send_data() instead ? > Is there any Rails support for my problem or do I have to implement > this myself ?send_file and send_data do not handle requests with a Range header. If you choose to add support, please contribute a patch + tests :) In the first response, use a 200 status and tell the browser that you support Range requests: headers[''Status''] = ''200 OK'' # unnecessary since it''s the default headers[''Accept-Ranges''] = ''bytes'' In subsequent requests, the browser may send a Range header like: Range: bytes=1234- to indicate that it wants from byte 1234 to the end of the file. In response: headers[''Status''] = ''206 Partial Content'' headers[''Accept-Ranges''] = ''bytes'' headers[''Content-Range''] = "bytes #{begin_range}-#{end_range}/# {file.content_length}" headers[''Content-Length''] = (end_range - begin_range).to_s You''ll also need to handle conditional GET (headers such as If- Modified-Since, If-Range, etc.), send status 416 for unsatisfiable ranges, and deal with ''*'' ranges. You must also send ETag headers for some browsers (Internet Explorer) to even try a Range request. The easiest path is to serve the file directly from Apache or lighttpd. If you''re using send_file in order to authorize downloads, investigate modules such as lighttpd''s mod_secdownload. Good luck! jeremy -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.2 (Darwin) iD8DBQFDgdA7AQHALep9HFYRAuBzAKCX8K0Rb/S2x6bOPprJCuxdNeE0SwCg2Tsq DVofu4FfIxNGX24JuaEJSKE=Jr3e -----END PGP SIGNATURE-----
gornack wrote:> Any ideas ? > Should I use send_data() instead ? > Is there any Rails support for my problem or do I have to implement this > myself ? > > Thanks > > Mike > > -- > Michael BAUDINO > EPITA 2007 > KameHouse Prod.use sftp...http was not made to transfer big files... Mikkel -- Posted via http://www.ruby-forum.com/.
Jeremy Kemper wrote:> -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > On Nov 21, 2005, at 5:06 AM, Michael Baudino wrote: > >> I''m trying to send large files (160MB - 1.5GB) using send_file(), >> it''s working perfectly except that I can''t figure out how to make the >> downloads resumable. >> If a download fails, I have to re-download it from scratch. >> As I''m dealing with large files I can''t set :stream => false >> >> Here is how I call send_file from my controller : >> >> send_file(@path, :type => (MIMETYPES[File.extname(@path)] || >> ''application/octet-stream'')) if File.file?(@path) >> >> Any ideas ? >> Should I use send_data() instead ? >> Is there any Rails support for my problem or do I have to implement >> this myself ? > > > send_file and send_data do not handle requests with a Range header. > If you choose to add support, please contribute a patch + tests :) > > In the first response, use a 200 status and tell the browser that you > support Range requests: > headers[''Status''] = ''200 OK'' # unnecessary since it''s the default > headers[''Accept-Ranges''] = ''bytes'' > > In subsequent requests, the browser may send a Range header like: > Range: bytes=1234- > to indicate that it wants from byte 1234 to the end of the file. > > In response: > headers[''Status''] = ''206 Partial Content'' > headers[''Accept-Ranges''] = ''bytes'' > headers[''Content-Range''] = "bytes #{begin_range}-#{end_range}/# > {file.content_length}" > headers[''Content-Length''] = (end_range - begin_range).to_s > > You''ll also need to handle conditional GET (headers such as If- > Modified-Since, If-Range, etc.), send status 416 for unsatisfiable > ranges, and deal with ''*'' ranges. You must also send ETag headers for > some browsers (Internet Explorer) to even try a Range request. > > The easiest path is to serve the file directly from Apache or > lighttpd. If you''re using send_file in order to authorize downloads, > investigate modules such as lighttpd''s mod_secdownload.With PHP I use PEAR::HTTP_Download - http://pear.php.net/package/HTTP_Download It works really well and if somebody is planning to implement something like this in Rails/Ruby then the PHP sourcecode might be a good place to start. HTH, Jeroen
Jeremy Kemper wrote:> -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > On Nov 21, 2005, at 5:06 AM, Michael Baudino wrote: > >> I''m trying to send large files (160MB - 1.5GB) using send_file(), >> it''s working perfectly except that I can''t figure out how to make the >> downloads resumable. >> If a download fails, I have to re-download it from scratch. >> As I''m dealing with large files I can''t set :stream => false >> >> Here is how I call send_file from my controller : >> >> send_file(@path, :type => (MIMETYPES[File.extname(@path)] || >> ''application/octet-stream'')) if File.file?(@path) >> >> Any ideas ? >> Should I use send_data() instead ? >> Is there any Rails support for my problem or do I have to implement >> this myself ? > > > send_file and send_data do not handle requests with a Range header. > If you choose to add support, please contribute a patch + tests :) > > In the first response, use a 200 status and tell the browser that you > support Range requests: > headers[''Status''] = ''200 OK'' # unnecessary since it''s the default > headers[''Accept-Ranges''] = ''bytes'' > > In subsequent requests, the browser may send a Range header like: > Range: bytes=1234- > to indicate that it wants from byte 1234 to the end of the file. > > In response: > headers[''Status''] = ''206 Partial Content'' > headers[''Accept-Ranges''] = ''bytes'' > headers[''Content-Range''] = "bytes #{begin_range}-#{end_range}/# > {file.content_length}" > headers[''Content-Length''] = (end_range - begin_range).to_s > > You''ll also need to handle conditional GET (headers such as If- > Modified-Since, If-Range, etc.), send status 416 for unsatisfiable > ranges, and deal with ''*'' ranges. You must also send ETag headers for > some browsers (Internet Explorer) to even try a Range request. > > The easiest path is to serve the file directly from Apache or > lighttpd. If you''re using send_file in order to authorize downloads, > investigate modules such as lighttpd''s mod_secdownload. > > Good luck! > > jeremy > -----BEGIN PGP SIGNATURE----- > Version: GnuPG v1.4.2 (Darwin) > > iD8DBQFDgdA7AQHALep9HFYRAuBzAKCX8K0Rb/S2x6bOPprJCuxdNeE0SwCg2Tsq > DVofu4FfIxNGX24JuaEJSKE> =Jr3e > -----END PGP SIGNATURE-----Thanks for your fast answer. Finally, I chose to serve the file directly from the webserver, as you suggested. that''s a lot easier, you were right ;) Thanks to all of you who answered. Mike -- Michael BAUDINO EPITA 2007 KameHouse Prod
Hi: I would like to have one drop down list control another so that if list one were companies and the second were employees, then once a selection was made in the companies drop down list, only employees of that company would show up in the second list. Pretty standard stuff and a good use of Ajax (I assume). I''m not asking for an answer (unless you''d truly like to give me an answer) but where is the best place I can look for the clearest explanation of how that can be done? Thanks in advance, bruce
Hi: I am re-posting this. Not only would the answer be useful to me, but surely to a lot of other people also. As I say, I don''t need an answer but I would like to know where to look for an answer. Trawling has not yet brought me satisfaction. thanks in advance, bruce On 29-Nov-05, at 1:04 PM, Bruce Balmer wrote:> Hi: > > I would like to have one drop down list control another so that if > list one were companies and the second were employees, then once a > selection was made in the companies drop down list, only employees > of that company would show up in the second list. Pretty standard > stuff and a good use of Ajax (I assume). > > I''m not asking for an answer (unless you''d truly like to give me an > answer) but where is the best place I can look for the clearest > explanation of how that can be done? > > Thanks in advance, > > bruce > > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails
It is 2am so this example may not be 100% correct as I am doing it from memory. :P The view will start off by populating the company select box with all available companies. By default the employee select box will be disabled until a company is selected. Once selected, the change to the company select box will trigger a call to the lookup_employees method of the controller to get the employees that are associated with the company_id selected. On success, it will rewrite what is in the ''employee_container'' DOM span object with the employee populated select box. There are some fancy things you can do like adding spinners to show progress when the employee select box is being populated that I have not included here. Hope this gets you off to the right start. # View <%= select ''client'', ''company_id'', @companies, { :prompt => true } %> <span id="employee_container"> <%= select_tag ''company'', nil, { :disabled => ''disabled'' } %> </span> <%= observe_field( :client_company_id, :update => :employee_container, :url => { :controller => ''client'', :action => :lookup_employees }, :with => "''company_id=''+escape(value)") %> # Controller def new @companies = Company.find(:all).collect {|co| [co.name, co.id]} end def lookup_employees @employees = Employee.find_all_by_company_id(@params[:company_id]).collect {|emp| [emp.name, emp.id]} render :inline => "<%= select ''company'', ''employee_id'', @employees, { :prompt => true } %>" end -- Posted via http://www.ruby-forum.com/.
Bruce Balmer wrote:> Hi: > > I am re-posting this. Not only would the answer be useful to me, but > surely to a lot of other people also. As I say, I don''t need an > answer but I would like to know where to look for an answer. Trawling > has not yet brought me satisfaction. > > thanks in advance,Ok from my understanding of your use-case, I''ve done something exactly the same as this using DWR on a recent J2EE project, now translating that into ruby... You''d need to add the correct event handlers to each of your drop down lists, so for example if you have companies / employees, you''d need some kind of listener for companies that sent a link_to_remote onChange to your controller, then the controller (say companies_controller) would have a method similar to ... # assume that each item in the companies list has a unique id that matches said id in database def update_employees_list employees_for_x = Employee.find(''where company = ?'', params[:id]) render :partial => ''employees_list'', :object => @employees_for_x #assuming a partial which contains the new drop down list end This method should replace the original employee_list with one containing the correct data I don''t know of any ''here''s the code for exactly what you want to do'' web-sites out there, but this should get you going in the right direction. http://script.aculo.us is always useful for seeing some AJAX work (in rails). For the general strategy, you can look at DWR (google for it) and they actually have an example of exactly what you want: in Java. Kev