Я унаследовал приложение 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
Извлечение изображения и его поворот прекрасно работают в работающем приложении в производстве и разработке. Однако модульный тест терпит неудачу с
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'
Причина в том, что когда метод модели вызывается в контексте модульного теста, open(self.public_filename)
возвращает объект StringIO
, содержащий данные изображения. Метод path
для этого объекта возвращает nil
, а MiniMagick::Image.from_file
взрывается.
Когда тот же самый метод модели вызывается из PhotosController
, open(self.public_filename)
возвращает экземпляр FileIO
, связанный с файлом с именем, например, /tmp/open-uri7378-0
, и этот файл содержит данные изображения.
Подумав, что причиной должна быть какая-то разница в среде между тестированием и разработкой, я запустил консоль в среде разработки. Но, как и в модульном тесте, open('http://...')
вернул StringIO
, а не FileIO
.
Я проследил свой путь через open-uri и весь соответствующий код для конкретного приложения и не могу найти причину разницы.