Ответ 1
Чтобы отправить файл с вашего веб-сервера,
-
вам нужно скачать его с S3 (см. @nzajt answer) или
-
вы можете
redirect_to @attachment.file.url
У меня есть ссылка для загрузки в моем приложении, из которой пользователи могут скачивать файлы, хранящиеся на 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?
Чтобы отправить файл с вашего веб-сервера,
вам нужно скачать его с S3 (см. @nzajt answer) или
вы можете redirect_to @attachment.file.url
Вы также можете использовать 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
не приводит к ожидаемой "загрузке браузера".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 %>
Что это.
Если вы по-прежнему хотели бы сохранить действие download
по какой-либо причине, просто используйте это:
В attachments_controller.rb
def download
redirect_to @attachment.download_url
end
Благодаря guilleva за его руководство.
Следующее - это то, что отлично работает для меня. Получение необработанных данных из объекта 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
Я только что перенесла мою папку 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
Файл сохраняется в поле attachment
объекта DriveDocument
.
Надеюсь, это поможет.