Почему Ruby open-uri open возвращает StringIO в моем модульном тесте, но FileIO в моем контроллере?
-
22-08-2019 - |
Вопрос
Я унаследовал приложение Rails 2.2.2, которое хранит загруженные пользователями изображения на Amazon S3. Модель Photo
на основе attachment_fu предлагает метод rotate
, который использует open-uri
для извлечения изображения из S3 и MiniMagick для выполнения поворота.
Метод rotate
содержит эту строку для получения изображения для использования с MiniMagick:
self.public_filename
возвращает что-то вроде
Получение изображения и его вращение отлично работают в работающем приложении в производстве и разработке. Однако модульный тест не проходит с
родовое слово Причина в том, что когда метод модели вызывается в контексте модульного теста, 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 и весь соответствующий код для конкретного приложения и не нашел причин для разницы.
Решение
Код, отвечающий за это, находится в классе Buffer в open-uri.Он начинается с создания объекта StringIO и создает фактический временный файл в локальной файловой системе только тогда, когда данные превышают определенный размер (10 КБ).
Я предполагаю, что любые данные, которые загружает ваш тест, достаточно малы, чтобы их можно было хранить в StringIO, а изображения, которые вы используете в реальном приложении, достаточно велики, чтобы требовать TempFile.Решение состоит в том, чтобы использовать методы, общие для обоих классов, в частности метод чтения, с MiniMagick :: Image # from_blob:
родовое словоДругие советы
Библиотека open-uri использует константу для установки предельного размера 10 КБ для объектов StringIO.
родовое словоВы можете изменить этот параметр на 0, чтобы open-uri никогда не создавал объект StringIO.Вместо этого это заставит его всегда создавать временный файл.
Просто вставьте это в инициализатор:
родовое словоВы не можете просто установить константу напрямую.Вам нужно фактически удалить константу, а затем установить ее снова (как указано выше), иначе вы получите предупреждение:
родовое слово ОБНОВЛЕНО 18.12.2012 : Rails 3 по умолчанию не требует OpenURI, поэтому вам нужно добавить require 'open-uri'
в верхней части инициализатора.Я обновил приведенный выше код, чтобы отразить это изменение.