Почему Ruby open-uri open возвращает StringIO в моем модульном тесте, но FileIO в моем контроллере?

StackOverflow https://stackoverflow.com/questions/694115

Вопрос

Я унаследовал приложение 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' в верхней части инициализатора.Я обновил приведенный выше код, чтобы отразить это изменение.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top