The only way to ensure reliable downloads is to move them outside the “public” path and transfer them to the user through a controller that checks authorization. The most efficient way to do this (what I know) is to use xsendfile.
So, for example, first you create a new directory in your application, say, “downloads” (you can name it, of course, and you can put it on any system available to your Rails server.)
mkdir downloads
Now create a new new route to load:
match '/downloads/*filename' => 'downloads#download'
Then create a new controller (or just an action in an existing controller)
class DownloadsController def download filename = [params[:filename], params[:format]].join('.') path = Rails.root.join( 'downloads', filename ) if File.exists?(path) && user.can_download?( filename ) send_file( path, x_sendfile: true ) else raise ActionController::RoutingError, "resource not found" end end end
Then you can go to
/downloads/path/my_file.txt
And let User # can_download? handle permission check.
It is slightly different if the files belong to the object, and are not free files in the file system, you will have to ask for identifiers, not file names, and determine the path from the associated model, but the principle is the same.
source share