Comment télécharger des fichiers image en Ruby

March 25, 2019
Rédigé par
Phil Nash
Twilion

Comment télécharger des fichiers image en Ruby

Avez-vous déjà eu besoin de télécharger et enregistrer une image dans votre application Ruby ? Continuez de lire pour savoir comment faire !

Bon vieux Ruby (Plain Old Ruby)

La façon la plus populaire de télécharger un fichier sans aucune dépendance est d’utiliser la librairie classique open-uri.

Kernel#open est une méthode que vous pouvez utiliser pour ouvrir des fichiers, des streams ou qui les process, les lit ou écrit dedans. Par exemple, vous pouvez ouvrir un fichier et lire son contenu avec le code suivant :

open("./test.txt") do |file| puts file.read end

open-uri étend Kernel#open afin qu’il puisse ouvrir les URL comme des fichiers. On peut l’utiliser pour télécharger une image et l’enregistrer comme fichier.

Pour ce faire, requêtez open-uri puis utilisez la méthode open pour accéder à une image depuis une URL. Vous pouvez ensuite ouvrir un fichier et écrire le contenu de l’image en haut de ce fichier. Ouvrez IRB et essayez ce qui suit :

require "open-uri"

open("https://s3.amazonaws.com/com.twilio.prod.twilio-docs/images/test.original.jpg") do |image|
  File.open("./test.jpg", "wb") do |file|
    file.write(image.read)
  end
end

Dans le répertoire dans lequel vous avez ouvert IRB, vous trouverez maintenant l’image que vous avez téléchargée.

C’est un succès mais cet exemple était un peu direct. Dans la pratique, vous voudriez pouvoir gérer les erreurs potentielles, comme les erreurs 404 pour une image manquante. De plus, il y a un tas d’autres risques potentiels avec l’utilisation de open-uri.

Les problèmes d’open-uri

En vérité, utiliser open-uri de cette façon n’est pas idéal. Premièrement, le code ci-dessus n’est pas très efficace niveau mémoire : il charge l’image entière dans la mémoire, puis écrit sur le disque. Il se trouve qu’open-uri a d’autres bizarreries… Janko Marohnić en a découvert un paquet alors qu’il travaillait sur Shrine. Notamment, open-uri:

Pour résoudre tout ça, Janko a créé le gem Down. Elle vous permet d’éviter ces soucis pour télécharger des fichiers de façon sécuritaire et efficace.

Améliorer les téléchargements avec la gem Down

Téléchargez la même image en utilisant  Down. Commencez par installer la gem :

gem install down

Vous pouvez télécharger l’image vers un Tempfile via Down.download :

require "down"

tempfile = Down.download("https://s3.amazonaws.com/com.twilio.prod.twilio-docs/images/test.original.jpg")

Si vous voulez sauvegarder ce fichier dans le système fichier, Down a une option pour ça. Passer un répertoire comme une option :destination sauvegardera le fichier dans ce répertoire.

require "down"

Down.download("https://s3.amazonaws.com/com.twilio.prod.twilio-docs/images/test.original.jpg", destination: "./")

Cela donnera au fichier téléchargé un nom aléatoire généré par Tempfile. Si vous voulez garder le nom du fichier à partir de l’URL, vous avez besoin d’un peu plus de travail. Dans ce cas, vous pouvez télécharger le fichier sur un Tempfile puis le déplacer sur un emplacement permanent dans votre disque.

Pour ce faire, utilisez FileUtils#mv qui prend deux arguments : le nom du fichier et la destination où vous souhaitez le déplacer. Pour obtenir le nom initial du fichier, l’objet Tempfile que Down renvoie possède une méthode original_filename dont vous pouvez vous servir.

require "down"
require "fileutils"

tempfile = Down.download("https://s3.amazonaws.com/com.twilio.prod.twilio-docs/images/test.original.jpg")
FileUtils.mv(tempfile.path, "./#{tempfile.original_filename}")

Vous avez efficacement téléchargé le fichier en toute sécurité et l’avez stocké de façon permanente sur votre disque dur.

Usage avancé

Down accepte aussi un paquet d’autres options, pour contrôler l’expérience de téléchargement. Par défaut, il autorise seulement 2 redirections, mais vous pouvez contrôler ça avec les options max_redirects. Vous pouvez aussi limiter la taille du fichier avec les options max_size. Elles empêchent les hackers de relier votre serveur à des téléchargements d’images géants. Si vous voulez télécharger un fichier qui fait 5MB au plus avec 5 redirections maximum, vous pouvez utiliser :

Down.download(
  "https://s3.amazonaws.com/com.twilio.prod.twilio-docs/images/test.original.jpg",
  max_redirects: 5,
  max_size: 5 * 1024 * 1024
)

Il y a plus d’options dans la documentation, dont comment streamer des fichiers et changer le back-end de la gem de open-uri et Net::HTTP à HTTP.rb ou Wget.

Prochaines étapes

Dans ce post, nous avons vu comment télécharger des images en utilisant open-uri et Down. Down est beaucoup plus sûr comme il nous épargne des boucles de redirection infinies et des injections de code à distance. Il est aussi plus simple d’utilisation comme il renvoie toujours un Tempfile et nous laisse facilement restreindre la taille du fichier.

Vous pourriez l’utiliser pour télécharger des médias à partir de Twilio MMS ou des messages WhatsApp, ou bien pour la connecter à Active Storage in Rails afin de donner plus d’options aux utilisateurs qui téléchargent des images.

Avez-vous utilisé des méthodes alternatives pour télécharger des images en Ruby ? Faites-le moi savoir sur Twitter : @philnash.