J'ai hérité d'une application Rails 2.2.2 qui stocke les images téléchargées par l'utilisateur sur Amazon S3. Le modèle Photo
basé sur attachment_fu propose une méthode rotate
qui utilise open-uri
pour récupérer l'image à partir de S3 et MiniMagick pour effectuer la rotation.Pourquoi Ruby open-uri ouvre-t-il un StringIO dans mon test unitaire, mais un FileIO dans mon contrôleur?
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
retours 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)
renvoie un objet StringIO
qui contient les données d'image. La méthode path
sur cet objet renvoie 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)
retourne une instance FileIO
liée à un fichier nommé, par exemple, /tmp/open-uri7378-0
et le fichier contient les données d'image. En pensant que la cause doit être une différence d'environnement entre le test et le développement, j'ai allumé la console dans l'environnement de développement. Mais tout comme dans le test unitaire, open('http://...')
a retourné un StringIO
, pas un FileIO
.
J'ai tracé mon chemin à travers open-uri et tout le code spécifique à l'application et ne trouve aucune raison pour la différence.
Ne faites pas 'open (self.public_filename) .read', vous ne savez pas quand le handle sera fermé. Utilisez à la place 'open (self.public_filename, &: read)', qui utilise la forme de bloc et se ferme explicitement une fois terminé. Et ce n'est pas vraiment plus de code. – apeiros
FYI, 'from_blob' est maintenant déprécié en faveur de' read'. Voir https://github.com/probablycorey/mini_magick/blob/f309fbf390cd21a845264bca9bec95b9bdae8029/lib/mini_magick.rb#L82 –