Use Rails 5.2 ActiveStorage to create and save pdf and later attach to email
Asked Answered
H

1

23

I am afraid i am getting something completely wrong with the new active storage feature. What I want to do is to create an pdf ( I am using WickedPdf ) and attach it to a model. Here is the first issue, The only chance i figured out so far is to write to a file first and then open this file to create the attachment.

self.document.attach( {
  filename: "filename.pdf",
  io: File.open(pdf_document)
})

Is there a way to create the attachment from a string?

Afterwards I try attach this file to a mail. This fails because it needs a file again, not a blob.

attachments[document.filename.to_s] = document.blob

Creating a file again seems really weird to me.

Can please someone enlighten me whats the proper way to achieve that without writing files at all? I seems unnecessary, inefficent and time consuming to me.

=====

Solution Part 2: So I managed to attach the document without creating a file

attachments[document.filename.to_s] = {:mime_type => 'application/pdf',
                               :content => document.attachment.blob.download }

Part one is still missing. Hope someone has an answer!

Heidiheidie answered 15/1, 2018 at 18:24 Comment(1)
I can't speak for active storage, but I can tell you that you absolutely can create an email attachment from a string. I have production code doing exactly that many times each day. Just for sake of testing, replace document.blob with 'this is a test' and confirm that the attachment is there. The issue is likely in the first part with active storage.Nash
B
34

I believe if you're generating something like a PDF, you'll want to use the io option when you attach. That's the way I'm doing things in an application now.

For example, here's what the documentation shows:

person.avatar.attach(params[:avatar]) # ActionDispatch::Http::UploadedFile object
person.avatar.attach(params[:signed_blob_id]) # Signed reference to blob from direct upload
person.avatar.attach(io: File.open("/path/to/face.jpg"), filename: "face.jpg", content_type: "image/jpg")
person.avatar.attach(avatar_blob) # ActiveStorage::Blob object

As it appears in the documentation, unless you have a ActionDispatch::Http::UploadedFile, you'll want to use the io option.

As for attaching the file to an email, you may have a couple options. If you still have access to the pdf_document, you could do this. I'm not sure exactly what type of object it is though.

attachments[document.filename.to_s] = pdf_document.read

Update

I've used wicked_pdf previously, but not for awhile. It looks like most of the generation methods return a string unless you request a file instead. You may already know this - just giving some background for the answer.

Since wicked_pdf can return a string, I think you can use StringIO to attach the file. For example:

pdf = WickedPdf.new.pdf_from_string("<h1>Hey</h1>")
self.document.attach(io: StringIO.new(pdf), filename: "file.pdf", content_type: "application/pdf")

StringIO does exactly as the name implies. It takes a string and makes it behave as an IO. Once you have an IO, you can use it with ActiveStorage as if you had an opened file.

Then, as you mentioned in your updated question, you can download the file and attach it to the email.

Blondellblondelle answered 15/1, 2018 at 23:49 Comment(4)
Thanks for the answer, but that is exactly the problem I am facing. If i do it like this I have to create a file on disc I dont need twice in this process. Isn't there any way to achieve it without writing to disk? Something like creating attachments from a string? For Mail and for ActiveStorage.Heidiheidie
@MarkusAndreas Please update your question to include the "without writing to disk" part. Maybe also provide some background on what requires you do things this way.Delusion
@MarkusAndreas I did some more research and updated this answer. Hope it helps.Blondellblondelle
Thanks a lot for the update! This works like a Charm!Heidiheidie

© 2022 - 2024 — McMap. All rights reserved.