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_stringandflash[:notice]from within a class methodself.pdfemailsince 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
PdfMailerclass 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,useremailfromcurrent_user.email.Inside the
PdfMailerclass 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.