What is the correct way to render_to_string in wicked pdf?
Asked Answered
T

4

5

This is what the documentation of wicked pdf specifies:

WickedPdf.new.pdf_from_string(
render_to_string(:pdf => "pdf_file.pdf", :template => 'templates/pdf.html.erb', :layout => 'pdfs/layout_pdf'), 
:footer => {:content => render_to_string({:template => 'templates/pdf_footer.html.erb', :layout => 'pdfs/layout_pdf'})}
)   

What i get is ActionView::MissingTemplate Even though i have pdf.html.erb in directory. I use a gen_pdf method in the application controller and an equivalent pdf.html.erb in the views/application folder. What am i missing.

Trapeziform answered 12/4, 2013 at 13:5 Comment(1)
Any chance you would select a correct answer here?Sibilant
S
12

Don't Use template.

I ran into the same problem as you. You have to render your PDF quite differently when you're doing it in a Controller action as opposed to a Mailer or something else.

First off, using template won't work. There's some other nuances but here is my implementation you can build off of:

notification_mailer.rb

def export
  header_html = render_to_string( partial: 'exports/header.pdf.erb', 
                                  locals:  { report_title: 'Emissions Export' } )

  body_html   = render_to_string( partial: "exports/show.pdf.erb" )

  footer_html = render_to_string( partial: 'exports/footer.pdf.erb' )

  @pdf = WickedPdf.new.pdf_from_string( body_html,
                                        orientation: 'Landscape',
                                        margin: { bottom: 20, top: 30 },
                                        header: { content: header_html },
                                        footer: { content: footer_html } )

  # Attach to email as attachment.
  attachments["Export.pdf"] = @pdf

  # Send email. Attachment assigned above will automatically be included.
  mail( { subject: 'Export PDF', to: '[email protected]' } )
end
Sibilant answered 5/8, 2015 at 20:45 Comment(0)
G
4

If you are using wicked_pdf and try to generate pdf outside of controller (i.e. in a cron job) you can do it this way (raild 4.1 +):

# app/renderers/pdf_renderer.rb

class PdfRenderer < ActionController::Metal
  include ActionView::ViewPaths
  include AbstractController::Rendering
  include AbstractController::Helpers
  include ActionController::Helpers
  include ActionView::Rendering
  include ActionView::Layouts
  include ActionController::Rendering
  include ActionController::Renderers
  include ActionController::Renderers::All

  append_view_path "app/views"

  View = Struct.new(:layout, :template, :locals)

  def render_pdf(view)
    wicked = WickedPdf.new
    pdf_string = render_to_string(template: view.template, layout: view.layout, locals: view.locals)
    # Make a PDF in memory
    pdf_file = wicked.pdf_from_string(pdf_string, pdf: "pdf_name",
                                      page_size: 'A4',
                                      wkhtmltopdf: ENV['WKHTMLTOPDF_EXECUTABLE_PATH'],
                                      margin: { top: '0.5in', bottom: '1in', left: '0.5in', right: '0.5in'}
    )

    # Write it to tempfile
    tempfile = Tempfile.new(['document', '.pdf'], Rails.root.join('tmp'))
    tempfile.binmode
    tempfile.write pdf_file
    tempfile.close
    tempfile
  end
end

and call this method:

  renderer = PdfRenderer.new
  pdf_view = PdfRenderer::View.new.tap do |v|
    v.template = "postal/#{template_file}.pdf.erb"
    v.layout = 'layouts/layout.pdf.erb'
    v.locals = {:user=> @user, :other_stuff => @details}
  end
  temp_pdf = renderer.render_pdf pdf_view

now you can use temp_pdf.path to do whatever you want with this file (i.e. send email)

you can read more about this way here: http://blog.arkency.com/2014/03/pdf-in-rails-without-controllers/

Guelph answered 13/4, 2017 at 8:44 Comment(2)
What are the modules for Rails 5?Latten
although this strategy worked for me, I didn't like how heavy it felt to create the PdfRenderer class. Instead, I preferred to simply use ApplicationController.renderwhich gave me everything wicked_pdf needed to be happy (since wicked_pdf is seemless from a controller context). I went ahead and posted the code that worked for me as an answer.Scrogan
U
2

You can have something like this inside your mailer:

class ReportMailer < ActionMailer::Base

  default :from => DEFAULT_FROM

  def report_pdf(user, bookings)
    @bookings = booking
    @user = user
    mail(:subject => 'Overtime', :to => user.email) do |format|
      format.text # renders overtime_pdf.text.erb for body of email
      format.pdf do
        attachments['monthly_report.pdf'] = WickedPdf.new.pdf_from_string(
            render_to_string(:pdf => 'monthly_report', :template =>
                'hospital_bookings/index.pdf.erb', :layouts => 'pdf.html')
        )
      end
    end
  end
end 

Hope this helps. Also if you want further help it would be ideal to post some of your code so that others can gain better understanding on what you have done and what your trying to achieve.

Ulm answered 12/4, 2013 at 17:37 Comment(0)
S
1

In case this helps someone else out: I had to generate a pdf via wicked_pdf from a job. This strategy worked for me from within the perform(*args) action of the job. WickedPDF appears to be intended to work from a controller context, so we just harness the power of controllers via ApplicationController.render:

generatedPdf  = WickedPdf.new.pdf_from_string(
  ApplicationController.render(
    template: "path/to/your/view/template.pdf.erb",
    layout: "layouts/your_wicked_pdf_layout.html.erb",
    locals: {some_var: @first_var, some_other_var: @second_var}
  )
)

save_path = Rails.root.join('public','your_saved_file.pdf')
File.open(save_path, 'wb') do |file|
  file << generatedPdf
end
Scrogan answered 16/12, 2022 at 19:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.