Ruby on Rails copy S3 file with special characters (%C5) in path - ruby-on-rails

I have a problem with my attachment system on web page. I store them on amazon S3 using paperclip. I have an option to copy attachment to new file. Everything works fine until there are polish special characters in title, like: ŁĄKA.jpg. Then I get an error:
Saving error: Appendix Paperclip::Errors::NotIdentifiedByImageMagickError
/Users/michal/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.5/lib/active_record/validations.rb:79:in `raise_record_invalid'
/Users/michal/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.5/lib/active_record/validations.rb:43:in `save!'
My code:
instance.appendixes.select {|a| a.temporary? && !a.appendix.exists?}.each do |a|
a.appendix = S3File.new(a.s3path)
a.process = false
a.appendix_url = nil
puts "CREATING NEW FILE from (temporary?) appendix: #{a.id}, path: #{a.s3path}, is_public: #{a.is_public}, determine_is_public: #{a.determine_is_public}"
a.is_public = a.determine_is_public
logger.debug("CREATING NEW FILE from (temporary?) appendix: #{a.id}, path: #{a.s3path}, is_public: #{a.is_public}, determine_is_public: #{a.determine_is_public}")
a.save! # bo delayed_job
end
I'm getting error on a.save! when path is like: appendixes/appendixes/242/original/%25C5%2581A%25CC%25A8KA.jpg, but works like charm when it is: appendixes/appendixes/243/original/laka.jpg or another file name without polish letters. Anybody had this kind of problem or have suggestions how to fix it?

Ok, I found what was wrong. I had to replace in a.s3path, the last part with original name (łąka.jpg) and everything works fine. So when I have:
S3File.new(appendixes/appendixes/243/original/łąka.jpg) it works good and finds the correct file on s3 server.

Related

How to create movie screenshot by ffmpeg in an amazon S3 path

I tried to create using ffmpeg a video screenshot from a remote video url in heroku console. Below is how I generated a movie instance and can see also an empty ready to be written file at S3. But the last line movie.screenshot is not working and generates this error:
FFMPEG::Error: Failed encoding.Errors: no output file created
Here is the code
s3 = Aws::S3::Resource.new(region: 'us-west-1')
bucket = s3.bucket("ruby-sample-kb-#{SecureRandom.uuid}")
bucket.create
object = bucket.object('ex-vid-test-kb.jpg')
object.put(acl: "public-read-write")
path = object.public_url
movie = FFMPEG::Movie.new("https://www.googleapis.com/download/storage/v1/b/seppoav/o/3606137_51447286560__56BAF29C-05CB-4223-BAE6-655DF2236321.MOV?generation=1492780072394755&alt=media")
movie.screenshot(path, :seek_time => 2)
I also tried the following line just if it should be written via put. What am I missing here?
object.put(acl: "public-read", body: movie.screenshot(path, :seek_time => 2))
I ended up convincing myself that ffmpeg movie.screenshot won't work for remote url path. So I had to figure out a solution where I can create tempfile in heroku system although the tempfiles stay per dyno.
file = Tempfile.new [prefix, suffix], "#{Rails.root}/app/assets/images/video_screenshots"
movie.screenshot(file.path)
This worked Ok.

Writing a file to a specific path in ruby taking the file name from excel

I am having some trouble writing a file to a specific path taking the file name from excel. Here is the code which I am using
out_file = File.new (#temp_path/ "#{obj_info[3].to_s}","w")
"#{obj_info[3].to_s}" = sample.txt
The value sample.txt comes from Excel during run time
#temp_path = "C:/Users/Somefolder/"
The error displayed is:
NoMethodError: undefined method `[]' for nil:NilClass
However, if the code is:
out_file = File.new ("#{obj_info[3].to_s}","w")
it successfully creates a file called sample.txt in the default directory. However, I want it to be stored in a specific directory and the file name needs to be passed from Excel.
Any help is much appreciated.
I believe your problem is because there a space between / and "
#temp_path/ "#{obj_info[3].to_s}
and I guess you want to build a path.
My advice is that you use File.join
f_path = File.join(#temp_path,obj_info[3].to_s)
out_file = File.new (f_path,"w")
Let me know if that solved the problem
You have 2 problems:
obj_info is nil so you make an error reading the value from excel, the error you get indicates it is on an array, in the code you published the only thing that's an array is what you read from excel.
Print the contents with p obj_info right before your code to check.
#temp_path and {obj_info[3].to_s} need to be concatenated to make a path.
You can do that with File.join like Mauricio suggests or like this
out_file = File.new ("#{#temp_path}/#{obj_info[3]}","w")
You can drop the to_s in this case.
It would be better if you publish the whole of your script that is meaningful.

Can't access File created by paperclip

Not sure what's the matter here :
file = Rails.root.join(Attachment.last.attachment.url(:original))
# => "/system/attachments/3/original/!my_awesome_pdf.pdf?1359735260"
Then I try and do this :
File.new(file, 'rb')
# => No such file or directory - /system/attachments/3/original/!my_awesome_pdf.pdf?1359735260
Why would that happen? I'm trying to be able to select the file to upload to GroupDocs.com
Ah the problem was that URI's will throw off Ruby from recognizing the name of the file. Removing the URI allows Ruby to open the file.

ruby reading files from S3 with open-URI

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.

Rails creating local xml file

I need to create a local xml file from a rails application and then copy it to a location on another server.
I have tried using the File.new option to create a new file but it gives me an error saying the file does not exist. After looking closer at the documentation it says that File.new opens a file that already exists.
I can't see any way to create a local file using Ruby, what am I missing?
Assuming you have built up your XML into a string, xml_string, you can do:
xml_file = open(filename, 'w')
xml_file.write xml_string
xml_file.close
Or using the block syntax to achieve this in one line:
File.open(local_filename, 'w') { |f| f.write(xml_string) }

Resources