Pourquoi Ruby retour open open-uri un StringIO dans mon test unitaire, mais un FileIO dans mon contrôleur?

StackOverflow https://stackoverflow.com/questions/694115

Question

Je Rails 2.2.2 hérité d'une application qui stocke les images envoyées par les utilisateurs sur Amazon S3. Le modèle de base Photo attachment_fu-offre une méthode qui utilise rotate open-uri pour récupérer l'image de S3 et MiniMagick pour effectuer la rotation.

La méthode rotate contient cette ligne pour récupérer l'image pour une utilisation avec MiniMagick:

temp_image = MiniMagick::Image.from_file(open(self.public_filename).path)

self.public_filename retourne quelque chose comme

http://s3.amazonaws.com/bucketname/photos/98/photo.jpg

Récupération de l'image et en le tournant fonctionne très bien dans l'application en cours d'exécution dans la production et le développement. Cependant, le test unitaire échoue avec

TypeError: can't convert nil into String
    /Users/santry/Development/totspot/vendor/gems/mini_magick-1.2.3/lib/mini_magick.rb:34:in `initialize'
    /Users/santry/Development/totspot/vendor/gems/mini_magick-1.2.3/lib/mini_magick.rb:34:in `open'
    /Users/santry/Development/totspot/vendor/gems/mini_magick-1.2.3/lib/mini_magick.rb:34:in `from_file'

La raison en est que, lorsque la méthode de modèle est appelé dans le cadre de l'essai de l'unité, open(self.public_filename) retourne un objet StringIO qui contient les données d'image. La méthode de path sur ce objet retourne nil et MiniMagick::Image.from_file explose.

Lorsque cette même méthode de modèle est appelé à partir du PhotosController, open(self.public_filename) renvoie une instance de FileIO liée à un fichier nommé, par exemple, /tmp/open-uri7378-0 et le fichier contient les données d'image.

Penser la cause doit être une différence entre l'environnement test et de développement, je pète la console dans l'environnement de développement. Mais tout comme dans le test unitaire, open('http://...') retourné un StringIO, pas a FileIO.

J'ai tracé mon chemin à travers ouvert uri et tout le code spécifique à l'application pertinente et ne trouve aucune raison pour la différence.

Était-ce utile?

La solution

Le code responsable de c'est dans la classe tampon en plein uri. Il commence par la création d'un objet StringIO et crée un seul fichier temp réel dans le système de fichiers local lorsque les données dépassent une certaine taille (10 Ko).

Je suppose que toutes les données de votre test chargement est assez petit pour se tenir dans un StringIO et les images que vous utilisez dans l'application réelle sont assez grandes pour justifier une tempfile. La solution est d'utiliser des méthodes qui sont communs aux deux classes, en particulier la méthode de lecture, avec MiniMagick :: Image # from_blob:

temp_image = MiniMagick::Image.from_blob(open(self.public_filename, &:read))

Autres conseils

La bibliothèque open-uri utilise une constante pour définir la limite de taille de 10 Ko pour les objets StringIO.

> OpenURI::Buffer::StringMax
=> 10240 

Vous pouvez modifier ce paramètre à 0 pour empêcher open-uri de créer jamais un objet StringIO. Au lieu de cela, ce sera le forcer à toujours générer un fichier temporaire.

Il suffit de jeter cela dans un initialiseur:

# Don't allow downloaded files to be created as StringIO. Force a tempfile to be created.
require 'open-uri'
OpenURI::Buffer.send :remove_const, 'StringMax' if OpenURI::Buffer.const_defined?('StringMax')
OpenURI::Buffer.const_set 'StringMax', 0

Vous ne pouvez pas définir simplement la constante directement. Vous devez supprimer réellement la constante puis réglez à nouveau (comme ci-dessus), sinon vous aurez un message d'avertissement:

warning: already initialized constant StringMax

MISE À JOUR 18/12/2012 : Rails 3 ne nécessite pas openURI par défaut, vous devez ajouter require 'open-uri' au sommet de l'initialiseur. Je mis à jour le code ci-dessus pour refléter ce changement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top