What is the difference between send_data and send_file in Ruby on Rails?
Which one is best for streaming and file downloads?
Please provide examples.
Solution 1:
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 )
Solution 2:
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.