Cannot send xlsx as attachment in Rails mailer - ruby-on-rails

I am trying to send an email containing a file attachment created by the user.
attachments[document.display_name] = File.read(document.public_filename)
This works in most conditions (including .docx, but fails for .xlsx files with the error:
invalid byte sequence in UTF-8
I am using attachment_fu to upload the attachments, and delayed_job to defer sending the emails, however the file I am trying to attach looks ok, and I can open it successfully outside the application.
I also saw a suggestion to change the code as follows, but it does not seem to help:
include an extra.
attachments[document.display_name] = { :content => File.read(document.public_filename), :transfer_encoding => :binary }
How can I make the code work for all attachment types?

You need to specify the mode or encoding to let it read the file as binary:
attachments[document.display_name] = File.read(document.public_filename, :mode => 'rb')
or
attachments[document.display_name] = File.read(document.public_filename, :encoding => 'BINARY')

Related

Email attachment for document files using rails action mailer

I am using Rails action mailer. I need to send a email with document(doc, docx, txt) as attachment. When I am attaching .txt files, the content in that txt file are viewing properly. But when I am trying to attach .doc or docx files, the content in that files are not displaying(it is converting into encoding format) Why is that happening. Is there any way to attach document files in email using rails action mailer.
def send_email(email, file)
#email = email
attachments['document.docx'] = File.read(file.path)
mail(from: #email, to: "aa#gmail.com", subject: "Document attachment")
end
original document attached
document received in email
Please guide me, if I am going wrong in some place.
Thanks in advance.
Try reading the file in binary mode (see binary file mode & :mode option:
attachments['document.docx'] = File.read(file.path, mode: 'rb')
In my case, Rails was adding a carriage return (aka "CR", or "\r") to every line in a CSV file that ended with either a "\n" (newline) or "\r".

Writing valid Excel file

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/

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

Decoding attachments using Mail Gem and Paperclip

I can receive emails via imap through the mail gem and would like to add the attachments to my model (called message). I receive this error based on my code taken from this blog post:
Encoding::UndefinedConversionError ("\xC1" from ASCII-8BIT to UTF-8):
My code:
mail.attachments.each_with_index do | attachment, index |
fake_file = AttachmentFile.new("test.jpg")
fake_file.write(attachment.decoded)
fake_file.flush
fake_file.original_filename = attachment.filename
fake_file.content_type = "image/gif"
#message.doc1 = fake_file if index == 0 and attachment.content_type.start_with?("image/")
end
Not sure what I am doing wrong to cause the error - maybe because the file is not read in binary mode? Another alternative was given in the same post:
file = StringIO.new(attachment.decoded)
file.class.class_eval { attr_accessor :original_filename, :content_type }
file.original_filename = attachment.filename
file.content_type = attachment.mime_type
This worked once with a gif but failed with a pdf, providing rollbacks. Also, I am on Windows for Dev, which has lead to problems with paperclip in the past (file size not read properly etc.)
The model has the following validations:
validates_attachment_content_type :doc1, :content_type => [ 'application/pdf', /image/ ], :message => "only pdf or img"
My log files are not that helpful, only normal output for the first and second option:
Command :: SET PATH=/usr/bin;%PATH% & file -b --mime "C:/Users/FOUNDA~1/AppData/Local/Temp/c81e728d9d4c2f636f067f89cc14862c20150412-5216-1utzh29.gif"
Not sure what kind of initialization there is for the mail gem - it is able to pull the emails correctly. Sorry, maybe I misunderstood your reply.
I made a mistake by having a validation that requested a certain structure for the filename, which was causing problems. The second option I listed works flawlessly now. Can't speak for the first one - the problems there would be the same, probably.

Rails 3, check CSV file encoding before import

In my app (Rails 3.0.5, Ruby 1.8.7), I created an import tool to import CSV data from file.
Problem: I asked my users to export the CSV file from Excel in UTF-8 encoding but they don't do it most of time.
How can I just verify if the file is UTF-8 before importing ? Else the import will run but give strange results. I use FasterCSV to import.
Exemple of bad CSV file:
;VallÈe du RhÙne;CÙte Rotie;
Thanks.
You can use Charlock Holmes, a character encoding detecting library for Ruby.
https://github.com/brianmario/charlock_holmes
To use it, you just read the file, and use the detect method.
contents = File.read('test.xml')
detection = CharlockHolmes::EncodingDetector.detect(contents)
# => {:encoding => 'UTF-8', :confidence => 100, :type => :text}
You can also convert the encoding to UTF-8 if it is not in the correct format:
utf8_encoded_content = CharlockHolmes::Converter.convert contents, detection[:encoding], 'UTF-8'
This saves users from having to do it themselves before uploading it again.
For 1.9 it's obvious, you just tell it to expect utf8 and it will raise an error if it isn't:
begin
lines = CSV.read('bad.csv', :encoding => 'utf-8')
rescue ArgumentError
puts "My users don't listen to me!"
end

Resources