Я сделал это на сайте, где люди платят за скачивание определенных файлов, а файлы хранятся в RAILS_ROOT/private
. Первое, что нужно знать, это то, что вы хотите, чтобы веб-сервер обрабатывал отправку файла, иначе ваше приложение будет задерживать передачу больших файлов, и это быстро остановит ваш сайт, если у вас есть какой-либо объем загрузки. Итак, если вам нужно проверить авторизацию в контроллере, то вам также нужен способ передать управление загрузкой обратно на веб-сервер. Лучший способ сделать это (насколько я знаю) - это заголовок X-Sendfile, который поддерживается Nginx, Apache (с модулем) и другими. С настроенным X-Sendfile, когда ваш веб-сервер получает заголовок X-Sendfile
от вашего приложения, он берет на себя отправку файла клиенту.
Если у вас есть X-Sendfile, работающий на вашем веб-сервере, вам пригодится такой метод частного контроллера:
##
# Send a protected file using the web server (via the x-sendfile header).
# Takes the absolute file system path to the file and, optionally, a MIME type.
#
def send_file(filepath, options = {})
options[:content_type] ||= "application/force-download"
response.headers['Content-Type'] = options[:content_type]
response.headers['Content-Disposition'] = "attachment; filename=\"#{File.basename(filepath)}\""
response.headers['X-Sendfile'] = filepath
response.headers['Content-length'] = File.size(filepath)
render :nothing => true
end
Тогда действие вашего контроллера может выглядеть примерно так:
##
# Private file download: check permission first.
#
def download
product = Product.find_by_filename!(params[:filename])
if current_user.has_bought?(product) or current_user.is_superuser?
if File.exist?(path = product.filepath)
send_file path, :content_type => "application/pdf"
else
not_found
end
else
not_authorized
end
end
Очевидно, что ваш метод авторизации будет отличаться, и вам нужно будет изменить заголовки, если вы предлагаете файлы, отличные от PDF, или если вы хотите, чтобы файл просматривался в браузере (избавьтесь от application/force-download
типа контента).