it-swarm.com.ru

Используете 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'

Файл определенно существует и общедоступен по ссылке в сообщении об ошибке.

Как разрешить пользователям загружать файлы S3?

55
David Tuite

Чтобы отправить файл с вашего веб-сервера,

  • вам нужно скачать его с S3 (см. ответ @ nzajt ) или

  • вы можете redirect_to @attachment.file.expiring_url(10)

29
sumskyi

Вы также можете использовать 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"
78
nzajt

Держите вещи простыми для пользователя

Я думаю, что лучший способ справиться с этим - использовать истекающий 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 %>

Вот и все.


Если по какой-то причине вы все еще хотите сохранить действие download, просто используйте это:

В вашем attachments_controller.rb

def download
  redirect_to @attachment.download_url
end

Спасибо Гильева за его руководство.

29
Joshua Pinter

Я только что перенес свою папку 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. Надеюсь, это поможет.

5
Kenneth John

Вот то, что в конечном итоге работает хорошо для меня. Получение необработанных данных из объекта S3 и последующее использование send_data для передачи их в браузер.

Использование документации по гемам aws-sdk, найденной здесь 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
4
David Morrow