ruby on rails - aws - ¿Usando send_file para descargar un archivo de Amazon S3?
aws en español (5)
Mantenga las cosas simples para el usuario
Creo que la mejor manera de manejar esto es usando una url S3 que expira. Los otros métodos tienen los siguientes problemas:
- El archivo se descarga al servidor primero y luego al usuario.
- El uso de
send_data
no produce la "descarga del navegador" esperada. - Vincula el proceso de Ruby.
- Requiere una acción de controlador de
download
adicional.
Mi implementación se ve así:
En su 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
En tus puntos de vista
<%= link_to ''Download Avicii by Avicii'', attachment.download_url %>
Eso es.
Si aún desea mantener su acción de download
por alguna razón, simplemente use esto:
En tus attachments_controller.rb
def download
redirect_to @attachment.download_url
end
Gracias a guilleva por su guía.
Tengo un enlace de descarga en mi aplicación desde el cual los usuarios deberían poder descargar los archivos que están almacenados en s3. Estos archivos serán accesibles públicamente en las URL que se parecen a
https://s3.amazonaws.com/:bucket_name/:path/:to/:file.png
El enlace de descarga golpea una acción en mi controlador:
class AttachmentsController < ApplicationController
def show
@attachment = Attachment.find(params[:id])
send_file(@attachment.file.url, disposition: ''attachment'')
end
end
Pero recibo el siguiente error cuando intento descargar un archivo:
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''
El archivo definitivamente existe y es accesible públicamente en la url en el mensaje de error.
¿Cómo permito que los usuarios descarguen archivos S3?
Acabo de migrar mi carpeta public/system
a Amazon S3. Las soluciones anteriores ayudan, pero mi aplicación acepta diferentes tipos de documentos. Entonces, si necesitas el mismo comportamiento, esto me ayuda:
@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
El archivo se está DriveDocument
en el campo de attachment
del objeto DriveDocument
. Espero que esto ayude.
Lo siguiente fue lo que terminó funcionando bien para mí. Obtener los datos brutos del objeto S3 y luego usar send_data
para pasarlos al navegador.
Usando la documentación de gemas aws-sdk
encontrada aquí http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/S3/S3Object.html
método de controlador completo
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
Para enviar un archivo desde su servidor web,
necesitas descargarlo de S3 (ver la respuesta de @nzajt ) o
puedes
redirect_to @attachment.file.expiring_url(10)
También puedes usar send_data
.
Me gusta esta opción porque tienes un mejor control. No está enviando usuarios a s3, lo que puede ser confuso para algunos usuarios.
Solo agregaría un método de descarga al 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
y agrega la ruta
get "attachments/download"