Я унаследовал приложение Rails 2.2.2, которое хранит загруженные пользователем изображения на Amazon S3. Модель Photo, основанная на attachment_fu, предлагает метод rotate, который использует open-uri для извлечения изображения из S3 и MiniMagick для выполнения вращения.
Метод rotate содержит эту строку для извлечения изображения для использования с MiniMagick:
temp_image = MiniMagick::Image.from_file(open(self.public_filename).path)
self.public_filename возвращает что-то вроде
http://s3.amazonaws.com/bucketname/photos/98/photo.jpg
Извлечение изображения и его вращение отлично работают в запущенном приложении в процессе производства и разработки. Однако unit test не работает с
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'
Причина в том, что когда метод модели вызывается в контексте unit test, open(self.public_filename) возвращает объект StringIO, который содержит данные изображения. Метод path этого объекта возвращает nil и MiniMagick::Image.from_file.
Когда этот самый метод модели вызывается из PhotosController, open(self.public_filename) возвращает экземпляр FileIO, связанный с файлом с именем, например, /tmp/open-uri7378-0, и файл содержит данные изображения.
Мысль о причинах должна быть некоторой экологической разницей между тестированием и разработкой, я запускал консоль в среде разработки. Но так же, как в unit test, open('http://...') вернул a StringIO, а не a FileIO.
Я проследил свой путь через open-uri и весь соответствующий код приложения и не нашел причин для разницы.