I am trying to download a zip file from an FTP server and save it in a temporary directory:
agent = Net::FTP.new
agent.connect(host, 21)
agent.login(user, pass)
agent.chdir(path)
agent.passive = true
file = agent.getbinaryfile(source_file, #file_path)
file.save!(#file_path)
However, it doesn't save the file because it's a String?
NoMethodError: undefined method `save!' for #<String:0x0000000cbc0398>
Is there another way to download zip files from an FTP server, or what am I missing?
Calling getbinaryfile is enough because Net::FTP#getbinaryfile will save the content in the specified path.
....
agent.getbinaryfile(source_file, #file_path)
The exception is thrown because the method returns a string and String does not have save! method. (Net::FTP does not have save! method neither)
Related
A file is being uploaded by rails and is logged as follows:
Parameters: {"authenticity_token"=>"[FILTERED]", "account"=>{"main_file"=>#<ActionDispatch::Http::UploadedFile:0x000000010922f7b8 #tempfile=#<Tempfile:/var/folders/jf/13j7d83s4_79kb5c4lkgdy0r0000gn/T/RackMultipart20221116-18676-44klzi.js>, #original_filename="smaller_sample_array.js"
The following does not work as the file is not a string per se
params[:account][:main_file] = params[:account][:main_file].reverse.chomp("revision.main.categories.part.0 = ".reverse).reverse
> NoMethodError (undefined method `reverse' for #<ActionDispatch::Http::UploadedFile:
while there is a method for renaming:
self.active_storage_object.blob.update(filename: "#{account_id}_#{self.active_storage_object.filename}.json")
what is a recommended method - or flow of methods - to alter (reverse chomp) the file contents?
Bote: if a file is first saved, then calling in this case account.file (Account has_one_attached :file), the view shows:
ActiveStorage::Attached::One:0x0000000106775338>
The file saved under the storage directory can be found, but have no idea how to access it from the rails controller.
I got an Endpoint that receives emails with .xlsx files as attachments. I want to save these file in my app, so I can later access the data.
After receiving the mail and its attachment - which has a mime_type of application/vnd.openxmlformats-officedocument.spreadsheetml.sheet- I call
path = "data/emails/#{attachment.filename}"
File.write(path, attachment.body.decoded)
but I get this error:
Encoding::UndefinedConversionError: "\x85" from ASCII-8BIT to UTF-8
When I use add .force_encoding('utf-8') to the decoded body, it does succeed, but the file it writes becomes invalid. I cannot open it normally, nor access its data.
How do I write a normal Excel file?
Does this work?
File.open( path, "w+b", 0644 ) { |f| f.write attachment.body.decoded }
Taken from here:
https://cbpowell.wordpress.com/2011/01/17/saving-attachments-with-ruby-1-9-2-rails-3-and-the-mail-gem/
I just started using resque to do some processing on some very large files in the background, and I'm having trouble figuring out how to pass a file to a resque worker. I use rails to handle the file upload, and rails creates an ActionDispatch::Http::UploadedFile object for each file uploaded from the form.
How do send this file to a resque worker? I tried sending a custom hash of just the pathname of the temporary file and original filename, but I can't reopen the temporary file in the resque worker anymore (just a normal Errno::ENOENT - No such file or directory) because rails seems to delete that temporary file after the request ends.
Http::UploadedFileisn't accessible once the request finishes. You need to write the file somewhere (or use s3 as temp storage). Pass resque the path to the file that you wrote.
I just spent two days trying to do this and finally figured it out. You need to Base64 encode the file so that it can be serialized into json. Then you need to decode it in the worker and create a new
ActionDispatch::Http::UploadedFile
Here's how to encode and pass to resque:
// You only need to encode the actual file, everything else in the
// ActionDispatch::Http::UploadedFile object is just string or a hash of strings
file = params[:file] // Your ActionDispatch::Http::UploadedFile object
file.tempfile.binmode
file.tempfile = Base64.encode64(file.tempfile.read)
Resque.enqueue(QueueWorker, params)
And Here's how to decode and convert back to an object within your worker
class QueueWorker
#queue = :main_queue
def self.perform(params)
file = params['file']
tempfile = Tempfile.new('file')
tempfile.binmode
tempfile.write(Base64.decode64(file['tempfile']))
// Now that the file is decoded you need to build a new
// ActionDispatch::Http::UploadedFile with the decoded tempfile and the other
// attritubes you passed in.
file = ActionDispatch::Http::UploadedFile.new(tempfile: tempfile, filename: file['original_filename'], type: file['content_type'], head: file['headers'])
// This object is now the same as the one in your controller in params[:file]
end
end
I'm having some problems reading a file from S3. I want to be able to load the ID3 tags remotely, but using open-URI doesn't work, it gives me the following error:
ruby-1.8.7-p302 > c=TagLib2::File.new(open(URI.parse("http://recordtemple.com.s3.amazonaws.com/music/745/original/The%20Stranger.mp3?1292096514")))
TypeError: can't convert Tempfile into String
from (irb):8:in `initialize'
from (irb):8:in `new'
from (irb):8
However, if i download the same file and put it on my desktop (ie no need for open-URI), it works just fine.
c=TagLib2::File.new("/Users/momofwombie/Desktop/blah.mp3")
is there something else I should be doing to read a remote file?
UPDATE: I just found this link, which may explain a little bit, but surely there must be some way to do this...
Read header data from files on remote server
Might want to check out AWS::S3, a Ruby Library for Amazon's Simple Storage Service
Do an AWS::S3:S3Object.find for the file and then an use about to retrieve the metadata
This solution assumes you have the AWS credentials and permission to access the S3 bucket that contains the files in question.
TagLib2::File.new doesn't take a file handle, which is what you are passing to it when you use open without a read.
Add on read and you'll get the contents of the URL, but TagLib2::File doesn't know what to do with that either, so you are forced to read the contents of the URL, and save it.
I also noticed you are unnecessarily complicating your use of OpenURI. You don't have to parse the URL using URI before passing it to open. Just pass the URL string.
require 'open-uri'
fname = File.basename($0) << '.' << $$.to_s
File.open(fname, 'wb') do |fo|
fo.print open("http://recordtemple.com.s3.amazonaws.com/music/745/original/The%20Stranger.mp3?1292096514").read
end
c = TagLib2::File.new(fname)
# do more processing...
File.delete(fname)
I don't have TagLib2 installed but I ran the rest of the code and the mp3 file downloaded to my disk and is playable. The File.delete would clean up afterwards, which should put you in the state you want to be in.
This solution isn't going to work much longer. Paperclip > 3.0.0 has removed to_file. I'm using S3 & Heroku. What I ended up doing was copying the file to a temporary location and parsing it from there. Here is my code:
dest = Tempfile.new(upload.spreadsheet_file_name)
dest.binmode
upload.spreadsheet.copy_to_local_file(:default_style, dest.path)
file_loc = dest.path
...
CSV.foreach(file_loc, :headers => true, :skip_blanks => true) do |row|}
This seems to work instead of open-URI:
Mp3Info.open(mp3.to_file.path) do |mp3info|
puts mp3info.tag.artist
end
Paperclip has a to_file method that downloads the file from S3.
How to check that my params['Filedata'] is corrupted or not?
I have function it's reading file from params['Filedata'] and writing it to the other file.
File.open(upload_file, "wb") { |f| f.write(params['Filedata'].read) }
this line working fine for me..
But when i am calling this function with delayed job function send_later than I am getting error with params['Filedata'].read.
I'm guessing params['Filedata'] refers to a uploaded file.
Rails handles uploaded data as temporary files, which are deleted after the request is completed. If you want to access the file later, you need to copy it to a more permanent location.