88

Which one is best for streaming and file downloads?

Please provide examples.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Mr. Black
  • 11,692
  • 13
  • 60
  • 85

2 Answers2

124
send_data(_data_, options = {})
send_file(_path_, options = {}) 

Main difference here is that you pass DATA (binary code or whatever) with send_data or file PATH with send_file.

So you can generate some data and send it as an inline text or as an attachment without generating file on your server via send_data. Or you can send ready file with send_file

data = "Hello World!"
send_data( data, :filename => "my_file.txt" )

Or

data = "Hello World!"
file = "my_file.txt"
File.open(file, "w"){ |f| f << data }
send_file( file )

For perfomance it is better to generate file once and then send it as many times as you want. So send_file will fit better.

For streaming, as far as I understand, both of this methods use the same bunch of options and settings, so you can use X-Send or whatever.

UPD

send_data and save file:

data = "Hello World!"
file = "my_file.txt"
File.open(file, "w"){ |f| f << data }
send_data( data )
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
fl00r
  • 82,987
  • 33
  • 217
  • 237
  • 1
    thanks @fl00r. Is there way to save the data as file and then send, using the send_data function?. Because, i needed a copy of the file in my server. How can i achieve that?. – Mr. Black Apr 04 '11 at 08:43
  • There's an error in your code: it should be `{ |f| f << data }`. – True Soft Sep 22 '11 at 10:22
  • Hi, I'm wondering if this answer is still relevant? I'm using Rails 3.2.16 now and using `send_file` I had to use the file itself, not the path in order to get it to work. Just wanted to update in case others run across this? – FireDragon Mar 18 '14 at 20:59
24

send_file may be faster than send_data

As fl00r mentioned, send_file takes a path, and send_data the data.

Therefore send_file is a subset of send_data, as you need a file on the filesystem: you could of course just read the file and use send_data on it. But send_file can be faster, so it is a performance / generality trade-off.

send_file can be faster because it can send the X-Sendfile header on Apache (X-Accel-Redirect on Nginx) instead of the file content, since it knows the path.

This header is consumed by the reverse proxy (Apache or Nginx) which normally runs in front of Rails in a production setup.

If X-Sendfile is present on the response, the reverse proxy ignores most of the current response, and builds a new one that returns the file at the given path.

Client <---> Internet <---> Reverse proxy <---> Rails

This is much more efficient since the reverse proxy is highly specialized at serving static files, and can do it much faster than Rails (which does not send the file data if X-Sendfile will be sent).

The typical use case of send_file is when you want to control the access permission of static files: you cannot put them under /public or else they would get served before Rails has a chance to decide. This is discussed at: Protecting the content of public/ in a Rails app

In order to use the X-Sendfile headers, you have to add:

config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx

to config/initializers/production.rb (or config/environment/production.rb in Rails 5.x), not application.rb, since in development you don't have a proxy server and you want send_file to actually send the data.

X-Sendfile is discussed on the Asset Pipeline Guide.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985