I have a page where the user can select multiple costprojects
to create a single pdf (including S3 attachments). It works fine - except if the user selects quite a few, then app will time out (30 sec).
So, I would like to create the pdf and email it in the background using gem 'delayed_job_active_record'
.
This works without delayed job:
def pdfemail
@costprojects = Costproject.find(params[:costproject_ids])
pdf = CombinePDF.new
@costprojects.each do |costproject|
@costproject = costproject
pdf2 = render_to_string pdf: "SLCO Captital Projects.pdf", template: "costprojects/viewproject", encoding: "UTF-8"
pdf << CombinePDF.parse(pdf2)
costproject.attachments.each do |attachment|
pdf << CombinePDF.parse( Net::HTTP.get( URI.parse( attachment.attach.url ) ) )
end
end
useremail = current_user.email
CostpdfMailer.costpdf_email(useremail,pdf).deliver
redirect_to :back
flash[:notice] = 'An Email containing a PDF has been sent to you!'
end
This was my first try that didn't work - I added:
handle_asynchronously :pdfemail
My second try:
def pdfemail
@costprojects = Costproject.find(params[:costproject_ids])
CostprojectsController.delay.pdfemail2(@costprojects)
end
def self.pdfemail2(costprojects)
@costprojects = costprojects
pdf = CombinePDF.new
@costprojects.each do |costproject|
@costproject = costproject
pdf2 = render_to_string pdf: "SLCO Captital Projects.pdf", template: "costprojects/viewproject", encoding: "UTF-8"
pdf << CombinePDF.parse(pdf2)
costproject.attachments.each do |attachment|
pdf << CombinePDF.parse( Net::HTTP.get( URI.parse( attachment.attach.url ) ) )
end
end
useremail = current_user.email
CostpdfMailer.costpdf_email(useremail,pdf).deliver
redirect_to :back
flash[:notice] = 'An Email containing a PDF has been sent to you!'
end
With the 2nd try, I get:
undefined method `render_to_string' for CostprojectsController:Class
The same render_to_string
worked when it was just pdfemail
.
3rd try:
pdf2 = CostprojectsController.new.render_to_string pdf: "SLCO Captital Projects.pdf", template: "costprojects/viewproject", encoding: "UTF-8"
With the 3rd try, @costproject
isn't getting passed to costprojects/viewproject.pdf.erb
You can't handle a controller action asynchronously.
And you can't call controller methods like
render
,render_to_string
andflash[:notice]
from within a class methodself.pdfemail
since those methods are instance methods on the controller.You'll have to separate out the pdf email logic from the controller response logic, like this:
Then in another file:
The
PdfMailer
class does not use any controller instance methods such asrender
,render_to_string
, orflash
, that has to be taken care of in the controller since you can't handle controller action asynchronously. Consequently you have to pass in the data you need, in this case thecostproject_ids
,useremail
fromcurrent_user.email
.Inside the
PdfMailer
class you'll have to generate the pdf in that loop with some other method than the controller'srender_to_string
. There's plenty of other tools for this here: https://www.ruby-toolbox.com/categories/pdf_generation.On your 3rd try: it isn't working because you're instantiating a new controller which doesn't have the @costproject instance variable set in it.