Search code examples
ruby-on-railsrubytwitterrubygems

How to tweet a jpeg/mp4 with the twitter gem in Rails through ActiveStorage S3 uploads?


I am trying to Tweet from my Rails App (7.0.1), Ruby (3.0.2). I am using the "twitter" gem and others to connect the Twitter account and publish to Twitter. Everything works fine as long as I am Tweeting text only. The Text is from "Model.content".

There is another "Model.media" that is an attachment with "has_one_attached" which I want to use for the media upload to Twitter. It is stored in AWS S3.

This is the how to Tweet text using the gem (just "content" and not "Model.content" because I am tweeting from the Model.rb itself):

client.update(content) It works and posts to Twitter fine.

To Tweet with media I can do it like that this according to the gem:

client.update_with_media(content, media)

The errors I am getting from the Rails logs are:

/Users/~/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-7.0.1/lib/active_support/core_ext/module/delegation.rb:307:in `method_missing': undefined method `merge' for #<ActiveStorage::Attached::One:0x00007fca71579048 @name="media", @record=#<...">> (NoMethodError)

If I try this:

client.update_with_media(content, Rails.application.routes.url_helpers.rails_blob_path(media, only_path: true))

The errors I am getting from the Rails logs are (same happens for .jpeg): /Users/~/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/twitter-7.0.0/lib/twitter/rest/upload_utils.rb:40:in `append_media': undefined method `eof?' for "/rails/active_storage/blobs/redirect/....mp4":String (NoMethodError)

I tried and looked for many solutions, they weren't specifically for this issue if I understand correctly. I feel I am missing a really small thing.

What is the best approach for this issue and how?

Links: Gem link: https://rubygems.org/gems/twitter

Gem quick guide: https://github.com/sferik/twitter/blob/master/examples/Update.md#update


Solution

  • According to the docs, media must be either a File or an array of Files. This method doesn't support direct uploads so you have to download the file from S3 first and then upload it to twitter.

    rails_blob_path returns a string and that's why it doesn't work. Also, this path is relative to your application domain, so you can't directly use it to reference files on your filesystem.

    ActiveStorage has an open method that yields a Tempfile. Fortunately they behave just like regular Files so you should be able to pass it to update_with_media. You can use it like so:

    media.open do |file|
      client.update_with_media(content, file)
    end
    

    It will create a temporary file on the filesystem.

    Alternatively, if your file is relatively small (which might not be the case with videos) you can use the download method. It will download the file and store it in memory:

    client.update_with_media(content, media.download)
    

    Side note: POST update_with_media is deprecated and shouldn't be used anymore.