¿Cómo puedo descargar un archivo desde una URL y guardarlo en Rails?


197

Tengo una URL a una imagen que quiero guardar localmente, para poder usar Paperclip para producir una miniatura para mi aplicación. ¿Cuál es la mejor manera de descargar y guardar la imagen? (Investigué el manejo del archivo ruby ​​pero no encontré nada).

Respuestas:


315

Prueba esto:

require 'open-uri'
open('image.png', 'wb') do |file|
  file << open('http://example.com/image.png').read
end

1
Esto funciona. Gracias. Intenté esto en una imagen. La imagen no se escribió correctamente en el archivo. Como si hubiera sido corrompido o algo así. También podría guiarme para hacer esto mismo en una aplicación Rails. ¿Puedo usar esto en una aplicación Rails?
Alok Swain

Sí, puede usarlo en una aplicación de rieles. El archivo no se escribe correctamente probablemente porque olvidé abrir el destino en modo de escritura binaria. Lo editaré ahora.
Levi

78
Esto lee todo el archivo en la memoria. La mejor manera esIO.copy_stream(open('http://example.com/image.png'), 'destination.png')
Janko-m

3
rieles 5, 2016, no necesitaba hacerlo require 'open-uri', solo usé el código debajo de él
Mirror318

1
Esta respuesta no me funcionó. la respuesta correcta está aquí: stackoverflow.com/a/29743394/1536309
Blair Anderson

147

Una versión aún más corta:

require 'open-uri'
download = open('http://example.com/image.png')
IO.copy_stream(download, '~/image.png')

Para mantener el mismo nombre de archivo:

IO.copy_stream(download, "~/#{download.base_uri.to_s.split('/')[-1]}")

2
Y más eficiente ya que la salida no se almacena como una cadena en la memoria. +1
Itay Grudev

2
Aunque en realidad es útil tener ambas respuestas mostradas, para que las personas como yo puedan ver ambas, pensar en las diferencias y luego elegir esta respuesta conscientemente por las razones correctas :)
Maxwell Evans

30

Si está utilizando PaperClip, la descarga desde una URL ahora se gestiona automáticamente.

Asumiendo que tienes algo como:

class MyModel < ActiveRecord::Base
  has_attached_file :image, ...
end

En su modelo, simplemente especifique la imagen como una URL, algo como esto (escrito en letra deliberada):

@my_model = MyModel.new
image_url = params[:image_url]
@my_model.image = URI.parse(image_url)

Probablemente quiera poner esto en un método en su modelo. Esto también funcionará bien en el sistema de archivos temporal de Heroku.

Paperclip lo tomará desde allí.

fuente: documentación de clip


44
Para futuros buscadores, Paperclip ya no permite esto de forma predeterminada: medium.com/in-the-weeds/…
Alex Dunae

14

Creo que esta es la forma más clara:

require 'open-uri'

File.write 'image.png', open('http://example.com/image.png').read

Sage soy nuevo en los carriles, donde puedo añadir este código en el modelo o el controlador o en la vista
adarsh

1
Depende, pero normalmente harías algo así dentro de un modelo o método de controlador. En un contexto de Rails, probablemente sea mejor usar las herramientas del marco como ActiveStorage, en lugar de escribir directamente en el disco.
Sage Ross el

10

Echa un vistazo a Net :: HTTP en la biblioteca estándar. La documentación proporciona varios ejemplos sobre cómo descargar documentos usando HTTP.


2
Esta respuesta necesita más visibilidad, ya que Kernel#openpermite no solo el acceso a los archivos, sino también la invocación del proceso mediante el prefijo de un símbolo de tubería (por ejemplo, open("| ls")). Por lo tanto, puede conducir a un grave riesgo de seguridad al usar entradas variables para el argumento de Kernel#open.
ConorB
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.