Sending Files or Data Streams to the Browser

Problem

You want to send e-book contents directly from your database to the browser as text and give the user the option to download a compressed version of each book.

Solution

You have a table that stores plain text e-books:

db/schema.rb:

ActiveRecord::Schema.define(:version => 3) do
 create_table "ebooks", :force => true do |t|
 t.column "title", :string
 t.column "text", :text
 end end

In the Document Controller, define a view that calls send_data if the :download parameter is present, and render if it is not:

app/controllers/document_controller.rb:

require 'zlib' 
require 'stringio' 
class DocumentController < ApplicationController
 def view
 @document = Ebook.find(params[:id])
 if (params[:download])
 send_data compress(@document.text), 
 :content_type => "application/x-gzip", 
 :filename => @document.title.gsub(' ','_') + ".gz" 
 else 
 render :text => @document.text
 end
 end
 protected
 def compress(text)
 gz = Zlib::GzipWriter.new(out = StringIO.new) 
 gz.write(text) 
 gz.close 
 return out.string 
 end 
end

Discussion

If the view action of the Document Controller is invoked with the URL , the e-book with an ID of 1 is rendered to the browser as plain text.

Adding the download parameter to the URL, which yields , requests that the contents of the e-book be compressed and sent to the browser as a binary file. The browser should download it, rather than trying to render it.

There are several different ways to render output in Rails. The most common are action renderers that process ERb templates, but it's also customary to send binary image data to the browser.

See Also