Uso de Send_File a una fuente remota (Ruby on Rails)

En mi aplicación, tengo un requisito que me está impidiendo.

Tengo un archivo almacenado en S3, y cuando un usuario hace clic en un enlace de mi aplicación, inicio sesión en la base de datos, hizo clic en el enlace, redujo su asignación de “crédito de descarga” en uno y luego quiero solicitar el archivo. descargar.

No solo quiero redirigir al usuario al archivo porque está almacenado en S3 y no quiero que tengan el enlace del archivo de origen (para poder mantener la integridad y el acceso)

Parece que send_file () no funciona con un archivo fuente remoto, ¿alguien recomienda una gem o un código adecuado que haga esto?

Deberá transmitir el contenido del archivo al usuario mientras lo lee desde el contenedor / objeto S3.

Si usa la biblioteca AWS :: S3 , algo como esto puede funcionar:

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

Este código se copia principalmente del código send_file que, por sí solo, funciona solo para archivos locales u objetos similares a archivos.

NB: De todos modos, aconsejaría que no se sirva el archivo desde el propio proceso de Rails. Si es posible / aceptable para su caso de uso, usaría un GET autenticado para servir los datos privados del depósito.

Al usar un GET autenticado, puede mantener el depósito y sus objetos privados, mientras permite un permiso temporal para leer el contenido de un objeto específico al crear una URL que incluya un token de firma de autenticación. El usuario simplemente se redirige a la URL autenticada, y el token puede hacerse válido por unos pocos minutos.

Usando el AWS :: S3 mencionado anteriormente, puede obtener una URL GET autenticada de esta manera:

  time_of_exipry = Time.now + 2.minutes S3Object.url_for(, , :expires => time_of_exipry) 

Puede leer el archivo desde S3 y escribirlo localmente en un directorio no público, luego usar X-Sendfile (apache) o X-Accel-Redirect (nginx) para servir el contenido.

Para nginx incluiría algo como lo siguiente en su configuración:

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

Luego en tu controlador de Rails, haces lo siguiente:

 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 

Una buena reseña del proceso está aquí.

Método completo de descarga de imágenes usando el archivo temporal (Rails probados 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