Ruby On Rails : sauvegarde de données dans un fichier temporaire

En Ruby, Si vous souhaitez créer un fichier temporaire (c’est à dire qui sera détruit par le système à la fin de son utilisation), vous pouvez utilisez la classe Tempfile.

Par exemple, vous avez besoin de créer un fichier zip temporaire qui se détruira une fois téléchargé par l’internaute.

Regardons comment fonctionne la classe Tempfile, c’est très simple, nous utilisons Ruby On Rails 5.

Tout d’abord nous déclarons notre fichier temporaire avec un nom et oui cela lui est nécessaire pour générer un nom temporaire à partir de la string passer en paramètres et de plein d’autre facteurs comme surement le temps.

zip_tmp = Tempfile.new("fichier_zip")

Ensuite nous ouvrons le zip et injectons les fichiers souhaités dedans comme dans l’article sur la gestion des zip en Rails (pensez à installer la gem rubyzip) :

    require 'zip'
    zip_tmp = Tempfile.new("fichier_zip")
    # Ouverture du fichier zip en écriture en passant le chemin vers le fichier ici le chemin vers notre fichier temporaire
    Zip::File.open(zip_tmp.path, Zip::File::CREATE) {
      |zipfile|
      # Insertion du contenu dans le fichier MonFichier lui même inséré dans le zip
      zipfile.get_output_stream("MonFichier") { |f| f.puts "ContenuDeMonFichier" }
    }

Vous aurez remarqué que le chemin du fichier temporaire zip_tmp se récupère naturellement par zip_tmp.path.

Après ce code nous avons un fichier temporaire qui contient notre fichier, ici pas besoin de « flusher » le fichier temporaire mais si nous avions un fichier temporaire csv écrit à partie d’une variable contenant le contenu il faut appliquer la méthode flush sur le fichier temporaire afin que l’écriture soit réellement réalisée sur le disque sinon impossible de faire appel à la méthode File.read sur le fichier temporaire comme par exemple :

    csv = "colonne1;colonne2;colonne3"
    csv_tmp = Tempfile.new("fichier_csv")
    csv_tmp << csv
    csv_tmp.flush
    p File.read(csv_tmp.path)

Si vous exécutez le code précédent sans l’appel à la méthode flush, la string retournée sera vide.

Envoyons maintenant le zip à notre internaute par la commande send_file :

    require 'zip'
    zip_tmp = Tempfile.new("fichier_zip")
    # Ouverture du fichier zip en écriture en passant le chemin vers le fichier ici le chemin vers notre fichier temporaire
    Zip::File.open(zip_tmp.path, Zip::File::CREATE) {
      |zipfile|
      # Insertion du contenu dans le fichier MonFichier lui même inséré dans le zip
      zipfile.get_output_stream("MonFichier") { |f| f.puts "ContenuDeMonFichier" }
    }
    send_file zip_tmp.path, filename: "fichier_zip.zip", type: "application/zip", disposition: :inline

La commande send_file passe la main au serveur web pour envoyer le fichier créé, si vous utilisez apache2 le fichier temporaire sera détruit une fois que l’instance d’apache2 sera détruite, ce qui est plutôt bien suivant les cas.

On aurait pu utiliser la méthode send_data en lisant le contenu du fichier temporaire puis en supprimant le fichier temporaire à la main pour être sûr qu’il soit détruit comme suit :

    require 'zip'
    zip_tmp = Tempfile.new("fichier_zip")
    # Ouverture du fichier zip en écriture en passant le chemin vers le fichier ici le chemin vers notre fichier temporaire
    Zip::File.open(zip_tmp.path, Zip::File::CREATE) {
      |zipfile|
      # Insertion du contenu dans le fichier MonFichier lui même inséré dans le zip
      zipfile.get_output_stream("MonFichier") { |f| f.puts "ContenuDeMonFichier" }
    }
    # Lecture du contenu du fichier temporaire zip
    contenu_zip_tmp = File.read(zip_tmp.path)
    # Destruction du fichier temporaire
    File.delete(zip_tmp.path) if File.exist?(zip_tmp.path)
    send_data contenu_zip_tmp, filename: "fichier_zip.zip", type: "application/zip", disposition: :inline

Le fichier temporaire sera supprimé avant l’envoi des données à l’internaute mais son contenu sera bien transmis mais personnellement dans ce cas je ne vois pas trop l’intérêt d’utiliser des fichiers temporaires s’il faut gérer la destruction soit même, l’utilisation d’une instance de la classe File ferait aussi bien.

Voilà pour l’utilisation de la classe Tempfile et des fichiers temporaires en Ruby.

Enjoy 😉

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.