Class: Download
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- Download
- Defined in:
- app/models/dataset/download.rb
Overview
A generated file, stored for the user to download
A download object is generated when a delayed job needs to send some data back to the user. We keep track of them in the database so that they can be expired and deleted when necessary.
All files are stored in RAILS_ROOT/downloads, not in the public tree, so that it is impossible to get the web server to serve the download files without passing through the RLetters's authentication. This folder is expected to be symlinked over from shared during a Capistrano deployment.
Class Method Summary (collapse)
-
+ (Download) create_file(basename) {|f| ... }
Creates a download object and file, then passes the file to the block.
-
+ (String) filename_to_path(fn)
private
private
Convert a filename to an absolute path.
-
+ (String) unique_filename(basename)
private
private
Get the path to a new download file.
Instance Method Summary (collapse)
-
- (undefined) delete_file
private
private
Delete the file when the database record is destroyed.
-
- (String) filename
Get the filename for this download.
-
- (undefined) send_file(controller)
Send this download to the user.
Class Method Details
+ (Download) create_file(basename) {|f| ... }
Creates a download object and file, then passes the file to the block
This function will create the file basename in the downloads folder (do not put a path of any sort on basename). A unique timestamp will be appended to the filename, and the file created. The file handle will then be passed to the provided block. Finally, the function creates a Download model, saves it in the database, and returns it.
Closing the file within the block is optional; it will be closed when the block terminates if it hasn't been already.
50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'app/models/dataset/download.rb', line 50 def self.create_file(basename) fn = unique_filename basename # Yield out to the block f = File.new(filename_to_path(fn), "w") yield f f.close unless f.closed? # Build a Download object and return it Download.create({ :filename => fn }) end |
+ (String) filename_to_path(fn) (private)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Convert a filename to an absolute path
145 146 147 |
# File 'app/models/dataset/download.rb', line 145 def self.filename_to_path(fn) Rails.root.join('downloads', fn) end |
+ (String) unique_filename(basename) (private)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Get the path to a new download file
This function will fetch a path for the file basename in the downloads folder (do not put a path of any sort on basename). A unique timestamp will be appended to the filename.
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'app/models/dataset/download.rb', line 119 def self.unique_filename(basename) ext = File.extname(basename) base = File.basename(basename, ext) # Add a timestamp to the basename = Time.now.utc.strftime('-%Y%m%d%H%M%S') ret = base + + ext fn = filename_to_path(ret) i = 0 while File.exists? fn i = i + 1 ret = base + + i.to_s + ext fn = filename_to_path(ret) # Runaway loop counter (DoS?) raise StandardError, "Cannot find a filename for download" if i == 100 end ret end |
Instance Method Details
- (undefined) delete_file (private)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Delete the file when the database record is destroyed
Just ignore if the file delete fails and raises an error. We'll have to manually clean the downloads directory in that case.
156 157 158 |
# File 'app/models/dataset/download.rb', line 156 def delete_file File::delete(filename) rescue nil end |
- (String) filename
Get the filename for this download
We save filenames in the database as relative paths, since the absolute paths may change over time across Capistrano deployments. This function wraps the query of the filename variable and converts it to an absolute path.
81 82 83 84 |
# File 'app/models/dataset/download.rb', line 81 def filename return nil unless filename? Download.filename_to_path(read_attribute(:filename)) end |
- (undefined) send_file(controller)
Send this download to the user
This function does its best to guess the MIME type by looking at the file extension.
97 98 99 100 101 102 103 104 105 106 |
# File 'app/models/dataset/download.rb', line 97 def send_file(controller) ext = File.extname(filename)[1..-1] mime_type = Mime::Type.lookup_by_extension(ext) content_type = mime_type.to_s unless mime_type.nil? content_type ||= 'text/plain' controller.send_file(filename, :x_sendfile => true, :type => content_type) end |