¿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.