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
CodePudding user response:
According to the docs, media
must be either a File
or an array of File
s. 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 File
s 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.