Использование Send_File для удаленного источника (Ruby on Rails) - PullRequest
12 голосов
/ 24 августа 2009

В моем приложении есть требование, которое ставит меня в тупик.

У меня есть файл, хранящийся на S3, и когда пользователь нажимает на ссылку в моем приложении, я регистрируюсь в БД, по которой он щелкнул по ссылке, уменьшаю размер скидки на «загрузку кредита» на один, а затем я хочу запросить файл для скачивания.

Я не просто хочу перенаправить пользователя в файл, потому что он хранится в S3, и я не хочу, чтобы у него была ссылка на исходный файл (чтобы я мог поддерживать целостность и доступ)

Похоже, что send_file () не будет работать с удаленным исходным файлом, кто-нибудь посоветует гем или подходящий код, который сделает это?

Ответы [ 3 ]

9 голосов
/ 24 августа 2009

Вам потребуется передать содержимое файла пользователю, читая его из корзины / объекта S3.

Если вы используете библиотеку AWS :: S3 , что-то вроде этого может работать:

 send_file_headers!( :length=>S3Object.about(<s3 object>, <s3 bucket>)["content-length"], :filename=><the filename> )
 render :status => 200, :text => Proc.new { |response, output|
   S3Object.stream(<s3 object>, <s3 bucket>) do |chunk|
     output.write chunk
   end
 }

Этот код в основном копируется из кода send_file, который сам по себе работает только для локальных файлов или файловых объектов

N.B. В любом случае, я бы посоветовал не обслуживать файл из самого процесса rails. Если это возможно / приемлемо для вашего случая использования, я бы использовал аутентифицированную GET для обслуживания личных данных из корзины.

Используя аутентифицированный GET, вы можете сохранять корзину и ее объекты закрытыми, одновременно предоставляя временное разрешение на чтение содержимого определенного объекта, создав URL-адрес, который содержит маркер подписи аутентификации. Пользователь просто перенаправляется на аутентифицированный URL, и токен можно сделать действительным всего за несколько минут.

Используя вышеупомянутый AWS :: S3, вы можете получить аутентифицированную ссылку GET следующим образом:

 time_of_exipry = Time.now + 2.minutes
 S3Object.url_for(<s3 object>, <s3 bucket>,
                  :expires => time_of_exipry)
4 голосов
/ 17 августа 2012

Метод загрузки полного изображения с использованием временного файла (проверенные рельсы 3.2):

def download
  @image = Image.find(params[:image_id])

  open(@image.url) {|img|
    tmpfile = Tempfile.new("download.jpg")
    File.open(tmpfile.path, 'wb') do |f| 
      f.write img.read
    end 
    send_file tmpfile.path, :filename => "great-image.jpg"
  }   
end
3 голосов
/ 24 августа 2009

Вы можете прочитать файл из S3 и записать его локально в непубличный каталог, а затем использовать X-Sendfile (apache) или X-Accel-Redirect (nginx) для обслуживания содержимого.

Для nginx вы должны включить что-то вроде следующего в вашу конфигурацию:


            location /private {
                                 internal;
                                 alias /path/to/private/directory/;
            }

Затем в вашем контроллере rails вы делаете следующее:


   response.headers['Content-Type'] = your_content_type
   response.headers['Content-Disposition'] = "attachment; filename=#{your_file_name}"
   response.headers['Cache-Control'] =  "private"
   response.headers['X-Accel-Redirect'] = path_to_your_file
   render :nothing=>true

Хорошая запись процесса: здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...