Я унаследовал приложение Rails 2.2.2, которое хранит загруженные пользователем изображения на Amazon S3. Модель Photo
, основанная на attachment_fu, предлагает метод rotate
, который использует open-uri
для получения изображения с S3 и MiniMagick для выполнения вращения.Почему Ruby open-uri open возвращает StringIO в моем модульном тесте, но FileIO в моем контроллере?
Метод 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
, не a FileIO
.
Я проследил свой путь через открытый uri и весь соответствующий код приложения и не нашел причин для разницы.
Не делайте 'open (self.public_filename) .read', вы не знаете, когда дескриптор будет закрыт. Вместо этого используйте 'open (self.public_filename, &: read)', который использует блочную форму и явно закрывается, когда это делается. И это не больше кода. – apeiros
FYI, 'from_blob' теперь устарел в пользу' read'. См. Https://github.com/probablycorey/mini_magick/blob/f309fbf390cd21a845264bca9bec95b9bdae8029/lib/mini_magick.rb#L82 –