Comment puis-je télécharger un fichier à partir d'une URL et l'enregistrer dans Rails?

197

J'ai une URL vers une image que je souhaite enregistrer localement, afin de pouvoir utiliser Paperclip pour produire une miniature pour mon application. Quelle est la meilleure façon de télécharger et d'enregistrer l'image? (J'ai examiné la gestion des fichiers rubis mais je n'ai rien trouvé.)

Alok Swain
la source

Réponses:

315

Essaye ça:

require 'open-uri'
open('image.png', 'wb') do |file|
  file << open('http://example.com/image.png').read
end
Levi
la source
1
Cela marche. Merci. J'ai essayé ceci sur une image. L'image n'a pas été correctement écrite dans le fichier. Comme s'il avait été corrompu ou quelque chose. Pourriez-vous également me guider pour faire de même dans une application Rails. Puis-je l'utiliser dans une application Rails?
Alok Swain
Oui, vous pouvez l'utiliser dans une application rails. Le fichier n'est pas écrit correctement parce que j'ai oublié d'ouvrir la destination en mode binaire d'écriture. Je vais éditer ça maintenant.
Levi
78
Cela lit le fichier entier en mémoire. La meilleure façon estIO.copy_stream(open('http://example.com/image.png'), 'destination.png')
janko-m
3
rails 5, 2016, je n'en avais pas besoin, j'ai require 'open-uri'simplement utilisé le code en dessous
Mirror318
1
cette réponse n'a pas fonctionné pour moi. la bonne réponse est ici: stackoverflow.com/a/29743394/1536309
Blair Anderson
147

Une version encore plus courte:

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

Pour conserver le même nom de fichier:

IO.copy_stream(download, "~/#{download.base_uri.to_s.split('/')[-1]}")
Heaume Clemens
la source
2
Et plus efficace car la sortie n'est pas stockée sous forme de chaîne en mémoire. +1
Itay Grudev
2
Bien qu'il soit en fait utile d'avoir les deux réponses affichées, pour que des gens comme moi puissent voir les deux, réfléchissez aux différences et choisissez cette réponse consciemment pour les bonnes raisons :)
Maxwell Evans
30

Si vous utilisez PaperClip, le téléchargement à partir d'une URL est désormais géré automatiquement.

En supposant que vous avez quelque chose comme:

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

Sur votre modèle, spécifiez simplement l'image en tant qu'URL, quelque chose comme ceci (écrit à la main délibérément):

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

Vous voudrez probablement mettre cela dans une méthode dans votre modèle. Cela fonctionnera également très bien sur le système de fichiers temporaire de Heroku.

Un trombone le prendra à partir de là.

source: documentation trombone

superluminaire
la source
4
Pour les futurs chercheurs, Paperclip ne permet plus cela par défaut: medium.com/in-the-weeds/…
Alex Dunae
14

Je pense que c'est la manière la plus claire:

require 'open-uri'

File.write 'image.png', open('http://example.com/image.png').read
Sage Ross
la source
sage je suis nouveau sur les rails, où je peux ajouter ce code dans le modèle ou le contrôleur ou en vue
adarsh
1
Cela dépend, mais généralement vous feriez quelque chose comme ça dans un modèle ou une méthode de contrôleur. Dans un contexte Rails, vous feriez probablement mieux d'utiliser les outils du framework comme ActiveStorage, plutôt que d'écrire directement sur le disque.
Sage Ross
10

Découvrez Net :: HTTP dans la bibliothèque standard. La documentation fournit plusieurs exemples sur la façon de télécharger des documents à l'aide de HTTP.

Pär Wieslander
la source
2
Cette réponse a besoin de plus de visibilité car elle Kernel#openpermet non seulement l'accès aux fichiers mais également le processus d'appel en préfixant un symbole de canal (par exemple, open("| ls")). Ainsi, cela peut entraîner un risque de sécurité grave en utilisant l'entrée variable de l'argument de Kernel#open.
ConorB