Rails 3 -Render PDF from view and attach to email
Asked Answered
K

2

20

I have been using Wicked_pdf to render a view as a PDF and actionmailer to send emails, but I can't get them to work together. I want to attach a PDF version of a certain view to an email using actionmailer and send it out by clicking a link or a button. I have a link_to command that sends out an email. Here is my controller that gets the email generated:

def sendemail
 @user = User.find(params[:id])
 Sendpdf.send_report(@user).deliver
 redirect_to user_path(@user)
 flash[:notice] = 'Email has been sent!'
end  

Here is what I have in my actionmailer:

class Sendpdf < ActionMailer::Base
default :from => "[email protected]"

def send_report(user)
@user = user
  attachment "application/pdf" do |a|
  a.body = #Something should go here, maybe WickedPDF.new.something?
  a.filename = 'MyPDF'
end     
mail(:to => user.email, :subject => "awesome pdf, check it")
end

end

I have seen many questions and answers, most dealing with Prawn. It seems like there should be a simple answer to this. Can anyone help?

UPDATE I'm grateful for a suggestion to use as an alternative option in the answer below. However, I would really like to learn how to render a view as a PDF and attach it to my email. I am open to using something different like Prawn or anything else if I need to.

Khano answered 23/4, 2011 at 6:16 Comment(0)
M
5

There are 2 ways for it.

  1. Either, you want the pdf to be embedded in the email you are sending, so that when the user downloads the pdf from the email, there is no request to the render new pdf action for your respective controller.
    I don't know how to do this efficiently because I have never done this before.

  2. Or, you just provide a link to the pdf in your email and when the user clicks on it, now the action for creating the pdf is called, and then the user can download it.
    This way, if there is a lot of burden on the server for the downloading of the pdf's, you can redirect these requests somewhere else. In short, there is a huge scope for efficiency.

A sample code for the 2nd method(code provided was written by using PDFkit, so change accordingly):

class PdfsController < ApplicationController
  def pdf
    respond_to do |format|
      format.pdf { render :text => wickedPDF.new( Pdf.find(params[:id]).content ).to_pdf }
    end
  end
...
end

Replace the Pdf.find(params[:id]).content as per your choice, and the to_pdf method, as per wickedPDF.

Then, you can simply pass the link for the pdf download in your email like this

<%= link_to "Download", pdf_pdf_path(pdf, :format => "pdf") %>

or whatever suits as per wickedPDF.

Monophony answered 23/4, 2011 at 10:45 Comment(2)
That is a great option, I didn't think of that actually. If I have my choice I would like to attach the PDF to the email, but until I figure that out, putting a "download" link in the email is a great idea, thanks!Khano
This doesn't answer the question as posed. Work arounds are often best used for comments, not answers.Diachronic
P
38

2 good ways to do this the way you want:

1: Create the pdf in the controller, then send that to the email as a param.

# controller
def sendemail
  @user = User.find(params[:id])
  pdf = render_to_string :pdf => 'MyPDF'
  Sendpdf.send_report(@user, pdf).deliver
  redirect_to user_path(@user)
  flash[:notice] = 'Email has been sent!'
end

# mailer
def send_report(user, pdf)
  @user = user
  attachments['MyPDF.pdf'] = pdf
  mail(:to => user.email, :subject => "awesome pdf, check it")
end

2: Create the pdf in the mailer directly (a little more involved, but can be called from a model)

def send_report(user)
  @user = user
  mail(:to => user.email, :subject => "awesome pdf, check it") do |format|
    format.text # renders send_report.text.erb for body of email
    format.pdf do
      attachments['MyPDF.pdf'] = WickedPdf.new.pdf_from_string(
        render_to_string(:pdf => 'MyPDF',:template => 'reports/show.pdf.erb')
      )
    end
  end
end
Polacre answered 28/4, 2011 at 3:48 Comment(5)
Thanks for answering this question. What I ended up doing was create an action to save a pdf to a file. Then in the action to send the mail I called this action, attached it to the email, then erased it from the file. Is that a bad way to do it? It works great.Khano
Not a bad way, but sometimes writing to the filesystem isn't desired, like on Heroku. Also, be careful that your files can't be moved or deleted by some other process.Polacre
@Polacre Just to add to this I have notice that majority of answers about WickedPDF are from you. I have searched high and low at all your answers and have the following set up: gist.github.com/anonymous/5229508 but cannot seem to nail it. Every solution that I have tried seems to be giving me a Template is missing. Look forward to your reply.Jolly
How to pass variables to template which is in render_to_string?Mesopause
@Mesopause render_to_string(pdf: 'MyPDF', template: 'reports/show.pdf.erb', locals: { var_1: 'variable 1' }) will make Variable: <%= var_1 %> available to an erb template.Polacre
M
5

There are 2 ways for it.

  1. Either, you want the pdf to be embedded in the email you are sending, so that when the user downloads the pdf from the email, there is no request to the render new pdf action for your respective controller.
    I don't know how to do this efficiently because I have never done this before.

  2. Or, you just provide a link to the pdf in your email and when the user clicks on it, now the action for creating the pdf is called, and then the user can download it.
    This way, if there is a lot of burden on the server for the downloading of the pdf's, you can redirect these requests somewhere else. In short, there is a huge scope for efficiency.

A sample code for the 2nd method(code provided was written by using PDFkit, so change accordingly):

class PdfsController < ApplicationController
  def pdf
    respond_to do |format|
      format.pdf { render :text => wickedPDF.new( Pdf.find(params[:id]).content ).to_pdf }
    end
  end
...
end

Replace the Pdf.find(params[:id]).content as per your choice, and the to_pdf method, as per wickedPDF.

Then, you can simply pass the link for the pdf download in your email like this

<%= link_to "Download", pdf_pdf_path(pdf, :format => "pdf") %>

or whatever suits as per wickedPDF.

Monophony answered 23/4, 2011 at 10:45 Comment(2)
That is a great option, I didn't think of that actually. If I have my choice I would like to attach the PDF to the email, but until I figure that out, putting a "download" link in the email is a great idea, thanks!Khano
This doesn't answer the question as posed. Work arounds are often best used for comments, not answers.Diachronic

© 2022 - 2024 — McMap. All rights reserved.