Использование send file для загрузки файла из Amazon S3?
у меня есть ссылка для загрузки в моем приложении, из которого пользователи должны иметь возможность загружать файлы, которые хранятся на s3. Эти файлы будут публично доступны по URL-адресам, которые выглядят примерно так
https://s3.amazonaws.com/:bucket_name/:path/:to/:file.png
ссылка для загрузки попадает в действие в моем контроллере:
class AttachmentsController < ApplicationController
def show
@attachment = Attachment.find(params[:id])
send_file(@attachment.file.url, disposition: 'attachment')
end
end
но я получаю следующее сообщение об ошибке при попытке загрузить файл:
ActionController::MissingFile in AttachmentsController#show
Cannot read file https://s3.amazonaws.com/:bucket_name/:path/:to/:file.png
Rails.root: /Users/user/dev/rails/print
Application Trace | Framework Trace | Full Trace
app/controllers/attachments_controller.rb:9:in `show'
файл определенно существует и является общедоступным по url-адресу в сообщении об ошибке.
как я разрешить пользователям загружать файлы S3?
5 ответов:
для того, чтобы отправить файл с вашего веб-сервера
вам нужно загрузить его из S3 (см. @nzajt это) или
вы можете
redirect_to @attachment.file.expiring_url(10)
вы также можете использовать
send_data
.мне нравится этот вариант, потому что у вас есть лучший контроль. Вы не отправляете пользователей в s3, что может привести к путанице для некоторых пользователей.
Я бы просто добавил метод загрузки в
AttachmentsController
def download data = open("https://s3.amazonaws.com/PATTH TO YOUR FILE") send_data data.read, filename: "NAME YOU WANT.pdf", type: "application/pdf", disposition: 'inline', stream: 'true', buffer_size: '4096' end
и добавить маршруту
get "attachments/download"
Держите Вещи Простыми Для Пользователя
Я думаю, что лучший способ справиться с этим-использовать истекающий url S3. Другие методы имеют следующие проблемы:
- файл сначала загружается на сервер, а затем на пользователя.
- используя
send_data
не производит ожидаемую "загрузку браузера".- связывает процесс Ruby.
- требуется дополнительный
download
действие контроллера.мой реализация выглядит так:
в своем
attachment.rb
def download_url S3 = AWS::S3.new.buckets[ 'bucket_name' ] # This can be done elsewhere as well, # e.g config/environments/development.rb url_options = { expires_in: 60.minutes, use_ssl: true, response_content_disposition: "attachment; filename=\"#{attachment_file_name}\"" } S3.objects[ self.path ].url_for( :read, url_options ).to_s end
Ваше мнение
<%= link_to 'Download Avicii by Avicii', attachment.download_url %>
Я только что мигрировал мой
public/system
папка для Amazon S3. Решения выше справки, но мое приложение принимает различные виды документов. Так что если вам нужно такое же поведение, это помогает мне:@document = DriveDocument.where(id: params[:id]) if @document.present? @document.track_downloads(current_user) if current_user data = open(@document.attachment.expiring_url) send_data data.read, filename: @document.attachment_file_name, type: @document.attachment_content_type, disposition: 'attachment' end
файл сохраняется в папке
следующее, что в конечном итоге работает хорошо для меня. Получение необработанных данных из объекта S3, а затем с помощью
send_data
чтобы передать это в браузер.С помощью
aws-sdk
документация gem находится здесь http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/S3/S3Object.htmlполный метод контроллера
def download AWS.config({ access_key_id: "SECRET_KEY", secret_access_key: "SECRET_ACCESS_KEY" }) send_data( AWS::S3.new.buckets["S3_BUCKET"].objects["FILENAME"].read, { filename: "NAME_YOUR_FILE.pdf", type: "application/pdf", disposition: 'attachment', stream: 'true', buffer_size: '4096' } ) end