The IO object for media must respond to to_io
If you’re getting this error with the Twitter
gem’s update_with_media
method. And googling around for the solution. I’m here to help you.
Twitter::Error::UnacceptableIO
The IO object for media must respond to to_io
Why this happens
When you call open
in Ruby with a URL. It uses Open::URI to open the file. If the file is under 10kb then it will return a StringIO
object. If the file is > 10kb, it will return a File
object.
Under normal circumstances, this is what we want. It’s more efficient.
The problem is, the Twitter
gem, does not handle the case where it is a StringIO
object. So you get the error Twitter::Error::UnacceptableIO
.
Solution
There are a bunch of ways to hack this so it works. Here is what I landed on as the least hacky way to fix this issue.
Add this module to your lib folder. This will handle both the normal and StringIO
cases for you by converting StringIO
’s to a File
.
# lib/twitter/image.rb
module Twitter::Image
# The Twitter gem is particular about the type of IO object it
# recieves when tweeting an image. If an image is < 10kb, Ruby opens it as a
# StringIO object. Which is not supported by the Twitter gem/api.
#
# This method ensures we always have a valid IO object for Twitter.
def self.open_from_url(image_url)
image_file = open(image_url)
return image_file unless image_file.is_a?(StringIO)
file_name = File.basename(image_url)
temp_file = Tempfile.new(file_name)
temp_file.binmode
temp_file.write(image_file.read)
temp_file.close
open(temp_file.path)
end
end
Now, when you’re tweeting an image. You can do this.
image = Twitter::Image.open_from_url(image_url)
twitter_client.update_with_media("Tweet tweet", image)
I hope this helps. If you come across an even better solution, let me know!