07-18-2023, 03:16 PM
I inherited a Rails 2.2.2 app that stores user-uploaded images on Amazon S3. The attachment_fu-based `Photo` model offers a `rotate` method that uses `open-uri` to retrieve the image from S3 and MiniMagick to perform the rotation.
The `rotate` method contains this line to retrieve the image for use with MiniMagick:
temp_image = MiniMagick::Image.from_file(open(self.public_filename).path)
`self.public_filename` returns something like
Retrieving the image and rotating it work just fine in the running application in production and development. However, the unit test fails with
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'
The reason is that when the model method is called in the context of the unit test, `open(self.public_filename)` is returning a `StringIO` object that contains the image data. The `path` method on this object returns `nil` and `MiniMagick::Image.from_file` blows up.
When this very same model method is called from the `PhotosController`, `open(self.public_filename)` returns a `FileIO` instance tied to a file named, eg, `/tmp/open-uri7378-0` and the file contains the image data.
Thinking the cause must be some environmental difference between test and development, I fired up the console under the development environment. But just as in the unit test, `open('http://...')` returned a `StringIO`, _not_ a `FileIO`.
I've traced my way through open-uri and all the relevant application-specific code and can find no reason for the difference.
The `rotate` method contains this line to retrieve the image for use with MiniMagick:
temp_image = MiniMagick::Image.from_file(open(self.public_filename).path)
`self.public_filename` returns something like
[To see links please register here]
Retrieving the image and rotating it work just fine in the running application in production and development. However, the unit test fails with
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'
The reason is that when the model method is called in the context of the unit test, `open(self.public_filename)` is returning a `StringIO` object that contains the image data. The `path` method on this object returns `nil` and `MiniMagick::Image.from_file` blows up.
When this very same model method is called from the `PhotosController`, `open(self.public_filename)` returns a `FileIO` instance tied to a file named, eg, `/tmp/open-uri7378-0` and the file contains the image data.
Thinking the cause must be some environmental difference between test and development, I fired up the console under the development environment. But just as in the unit test, `open('http://...')` returned a `StringIO`, _not_ a `FileIO`.
I've traced my way through open-uri and all the relevant application-specific code and can find no reason for the difference.