Import excel files using Paperclip, S3 and Roo - ruby-on-rails

I'm trying to import an excel file using Paperclip and save it to S3 then extract and parse using the Roo gem.
When I attempt something like this:
#excel = Excel.new(#manifest.attachment.url)
I get the following error:
http://s3.amazonaws.com/mybucket/attachments/22/manifest.xls?1343835058 is not an Excel file
I'm guessing the appended timestamp on the end of the filename is causing Roo to not think this is an Excel file.
How do i fix this?

To remove the timestamp you need to pass the 'false' argument in the url method.
For you : #excel = Excel.new(#manifest.attachment.url)
you should try with #excel = Excel.new(#manifest.attachment.url(:original, false)) then you will be getting the following url:
http://s3.amazonaws.com/mybucket/attachments/22/original/manifest.xls
But if you are trying to retrieve the image url then you should have #manifest.attachment.url(:large, false). Note: it can be :large, :medium or your customized styles in the model.
I hope that this might help you to solve your issues.
thanks

Related

How to open base64 spreadsheet on Ruby

I've been trying to manipulate a file that's base64 encoded that I'm recieving from my client.
I'm currently using https://github.com/zdavatz/spreadsheet/blob/master/GUIDE.md to manipulate it, however, there doesn't appear to be any way to open a file directly from the base64 blob, or should I write it and then read from it? can't that a potential security threat for the server?
for example, if I recieve a file :
file = params[:file] with contents:
data:application/vnd.ms-excel;base64,0M8R4KGxGuEAAAAAAAAAAAAAAAAAAAAAOwADAP7
(should I remove the data:application/vnd.ms-excel;base64, ?)
I'd like to open it with this:
Spreadsheet.client_encoding = 'UTF-8'
book = Spreadsheet.open "#{Rails.root}/app/assets/spreadsheet/event.xls"
(or with a blob or temp fle)
Sorry if it's pretty obvious, been looking for hours and there's not much info about it available, tried creating a temp file first but I don't think that's supported and there's not much I can get from the docs.
Shot in the dark: Maybe decode it, write to binary-enabled tempfile, and then feed that to Spreadsheet?
tmpfile = Tempfile.new.binmode
tmpfile << Base64.decode64(params[:file])
tmpfile.rewind
book = Spreadsheet.open(tmpfile)

Serving excel sheet (.xls) to browser for download using rails & angular

I am using spreadsheet gem to generate .xls file. After writing it to a file, I am trying to send to client browser for download.
Below is the code in rails
workbook = Spreadsheet::Workbook.new
# Constructed the data
file = "/path/to/file/sheet.xls"
workbook.write file
send_file file
This file when opened contains expected data in ideal format.
Below is the code in js:
CustomRestService.custom_post("report",{report_data: angular.toJson($scope.report_data)},"download_xls",{}).then (data)->
if data
hiddenElement = document.createElement('a')
angular.element(document.body).append(hiddenElement)
hiddenElement.href = 'data:attachment/xls,' + encodeURI(data)
hiddenElement.target = '_blank'
hiddenElement.download = "report.xls"
hiddenElement.click()
hiddenElement.remove()
But the file getting downloaded in browser contains junk data. I tried multiple solutions like below:
Using send_data, instead of send_file
Generated xls data and wrote to StringIO object to directly download
Constructed Blob object in js, with type as "application/vnd.ms-excel" and trying to download it.
All attempts failed, as I am missing something. All suggestions are welcome.
filename = "/path/to/file/sheet.xls"
tempfile = Tempfile.new(filename)
workbook = Spreadsheet::Workbook.new
...
workbook.write(tempfile.path)
send_file tempfile.path, :filename => filename

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

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.

Converting .txt file to .xml ruby on rails

I have a custom file type (.map) that I am unzipping from a Gzip file and then writing to a new file in order to pass it along to Paperclip and upload to s3. My problem is that the type should be an xml, while it is saving as a text document instead with all xml formatting correct. I need a way to convert it into the xml type and then save that as a new File object before passing it along.
Here is my code so far:
Zlib::GzipReader.open(f.tempfile) do |gz|
puts gz.orig_name
#tmp = File.new(gz.orig_name, "w+")
while chunk = gz.read(16*1024) do
#tmp.write(chunk)
end
end
reader = #tmp.read
s = location.posts.create!(
subject: #email.subject,
from: #email.from[:email],
mapfile: #tmp)
}
ideally i will be passing mapfile the xml type file, but right now it seems to be text
Update:
So now I have set my post.rb to do this, and added a name attribute to post containing the original file name:
has_attached_file :mapfile,
:preserve_files => "true",
:path =>
':rails_root/non-public/system/:id/:basename.:extension',
:url => '/:class/:id/mapfiles',
:s3_headers => lambda { |attachment| {'Content-Disposition' => "attachment; filename = #{attachment.name}"}}
And this works perfectly!
It sounds like you are talking about `Content-Type'. When you save a file to the filesystem, you can't set this: the system will decide what to use based on the file extension and possibly by analysing the contents, if it's a text file.
However, you can set the content type when you serve a file to someone's browser, and when you upload it to S3. See here for the latter Setting the Content-Type in direct to S3 upload using Rails and jQuery File Upload

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.

Resources