mileszs / wicked_pdf

PDF generator (from HTML) plugin for Ruby on Rails
http://www.mileszs.com/wicked-pdf-plugin
MIT License
3.53k stars 642 forks source link

ActionView::MissingTemplate after upgrade to rails 7 #1005

Open guemidiborhane opened 2 years ago

guemidiborhane commented 2 years ago

Issue description

We've been having issues with the render since our upgrade to rails 7.0 reporting that the template is not found even though the render code inside the controller didn't change. I can confirm that running the same version of wicked_pdf on rails 6.1 still works fine in production.

# ...
render pdf: @title, layout: 'pdf', orientation: 'Landscape', template: 'controller/action.html.erb',
           show_as_html: params.key?('debug'), margin: { top: 5, bottom: 5, left: 5, right: 5 },
           footer: { right: 'Page [page] / [topage]', font_size: 8 }
# ...

Expected or desired behavior

Renders the pdf like usual

System specifications

wicked_pdf gem version: master on github

wkhtmltopdf version: 0.12.6

platform/distribution and version: docker ruby 3.0.3 alpine image

unixmonkey commented 2 years ago

@guemidiborhane I'm not sure why this is yet, and am looking into it, but I was able to get it to work by changing template: 'controller/action.html.erb', to template: 'controller/action'. This should be a valid work-around for now.

Please try this and let me know how it goes!

guemidiborhane commented 2 years ago

@unixmonkey thanks for the reply, I actually need to use template: 'controller/action', format: [:html] in order for it to work, or change the view files extension to .pdf.erb

aliciapaz commented 2 years ago

Hello and thanks for this issue! I was having the same problem and was able to solve it using: template: 'controller/action', formats: [:html]

Note that is formats instead of format

guemidiborhane commented 2 years ago

@aliciapaz sorry for the typo, the issue is that it wasn't required previously

edgartheunready commented 2 years ago

I can confirm that using formats fixes this issue.

<%= render partial: "show", formats: :html %>

This issue can probably be closed since this is really caused by an underlying Rails change. My guess is that PDF generation is the only place I'll see this in my app because it's the only place where I want to render html when the request type is not ".html".

hybridspyda commented 2 years ago

Unfortunately I have been unable to solve this issue with the solutions given and instead updated my Gemfile to downgrade back to 6 😞

unixmonkey commented 2 years ago

@hybridspyda Let's schedule a quick screen-share for me to help you solve your issue. Shoot me an email and we'll coordinate a time.

Pyo25 commented 2 years ago

I was facing the same error since I upgraded to Rails 7.

My view file was named export_pdf.pdf.haml and my controller code looked like template: 'proposals/export_pdf.pdf.haml'.

I had to rename my file to export_pdf.html.haml and changed controller code to template: 'proposals/export_pdf' No need to set formats option.

@hybridspyda Maybe it can help you :)

spaci76 commented 2 years ago

I run i the same problem. My setup:

a fresh homebrew env:

my show section in the controller:

  def show
  @booking_statuses = BookingStatus.all
  respond_to do |format|
      format.html
      format.pdf do
        render pdf: "Contractnr: #{@booking.id}"
      end
    end
  end

The "show" View located at bookings/show.html.erb

The URL called http://localhost:3000/bookings/1.pdf but the show Template couldn't find.

The Errorouthput shows: Missing template bookings/show with {:locale=>[:de], :formats=>[:pdf], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :jbuilder]}. Searched in: * "/demo/app/views" * "/opt/homebrew/lib/ruby/gems/3.1.0/gems/actiontext-7.0.2.3/app/views" * "/opt/homebrew/lib/ruby/gems/3.1.0/gems/actionmailbox-7.0.2.3/app/views"

has anyone a hint for my. Thanks an Happy Easter!

goodanthony commented 2 years ago

This is what worked

respond_to do |format|
  format.html
  format.pdf do
    render pdf: "hello-filename", template: "hello/print_pdf", formats: [:html], disposition: :inline, layout: 'pdf'
  end
end

The filename
print_pdf.html.erb

Thanks to https://github.com/complygroup
mathieujobin commented 2 years ago

can you confirm if this is still a problem with recent master ? close if it isn't

yshmarov commented 2 years ago

I just tried doing it using the last release, and still had the "bug".

I had to use the above solution to make it work.

mathieujobin commented 2 years ago

Thanks @yshmarov we haven't merged our rails7 branch yet to production, so we'll keep an eye about this...

@spaci76 I recommend you get on the latest version of this gem.

Gibson2 commented 2 years ago

Hello!!!, I have this issue

image

How can I solve it?

mathieujobin commented 2 years ago

@Gibson2 your best bet is to try the above solution by @goodanthony.

gabrielboeker commented 1 year ago

this does not work for footer and header under rails 7 unfortunately.

 footer: { template: 'invoices/footer', 
                formats: [:html], 
                layout: 'pdf' 
             },

Does not throw an error like before but just does not displays the footer. Does anyone have an idea why?

EDIT:

The trick was to change the setting call for the footer to

footer: {
    content: render_to_string(
        'invoices/footer',
        formats: [:html],
        layout: 'pdf'
   )
},
Timmitry commented 1 year ago

Another gotcha: We were using formats: "html", which did not work anymore with Rails 7.0. However, changing it to a symbol formats: :html fixed the issue 🙄

johnchambers commented 1 year ago

Had this same issue with Rails 7 in production. I ran bundle update wkhtmltopdf-binary so it's now 0.12.6.6 (was 0.12.6.5) and it's now working.

gabriel-andreoli commented 1 year ago

I'm having the same problem and I've tested anything and everything that's here in this thread... Does anyone have any other possible solutions?

unixmonkey commented 1 year ago

@gabriel-andreoli Please provide more details if possible. What are your PDF templates named, and what folders are they in? What does your render call look like?

gabriel-andreoli commented 1 year ago

In lotes_controller:

  def gerar_etiqueta
    respond_to do |format|
      format.html
      format.pdf do
        render pdf: "teste_pdf_name", template: "lotes/gerar_etiqueta", format: :html, disposition: :inline, layout: 'pdf'
      end
    end
  end

My template in: views/lotes/gerar_etiqueta.html.erb

The problem: ActionView::MissingTemplate (Missing template lotes/gerar_etiqueta with {:locale=>[:"pt-BR", :pt], :formats=>[:pdf], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :haml, :jbuilder]}.

I already run the bundle install for gem 'wicked_pdf' and gem 'wkhtmltopdf-binary'.

unixmonkey commented 1 year ago

@gabriel-andreoli Ok, so this error message tells me that your render call is causing Rails to look for: app/views/lotes/gerar_etiqueta.pdf.erb (the :formats=>[:pdf] part), which is overriding your request for format: :html.

So either you can either:

No guarantees, but I think this will fix things for you.

gabriel-andreoli commented 1 year ago

Now it's working with the first solution and I also removed the exe path from the initializer .rb file...

Thank you so much!

ameft commented 1 year ago

I found myself with a similar error after upgrading to Rails 7. This was my initial working code:

WickedPdf.new.pdf_from_string(
  ActionController::Base.new.render_to_string(
    template: "model/action",
    layout: "layouts/pdf.html.erb",
  )
)

Which returned this error after the upgrade: ActionView::MissingTemplate (Missing template layouts/pdf.html.erb with {:locale=>[:it], :formats=>[:pdf], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby]} And this is how I had to change:

WickedPdf.new.pdf_from_string(
  ActionController::Base.new.render_to_string(
    template: "model/action",
    layout: "pdf",
  )
)

Additionally I had to rename layouts/pdf.html.erb to layouts/pdf.pdf.erb, otherwise it was ignored. No formats required in my case, as per other users.

srbong commented 1 year ago

I too am having this issue and none of the above solutions worked :( It works in Rails 6.1 but not 7.

my code looks like:

        render pdf: filename,
               disposition: 'attachment',
               layout: 'application.html',
               template: 'leadsheets/index.html',
               print_media_type: true
unixmonkey commented 1 year ago

@srbong Here's what I'd do to troubleshoot your issue:

  1. Comment out the print_media_type line, and maybe the disposition one (if it makes it easier to refresh the page)
  2. Comment out the layout line, does it render (though it might be wrong without the layout)
  3. Take .html off the template string, does it render or give you a better error message
  4. Add formats: :html and try again
  5. Change to formats :pdf and try again
  6. Add back options one at a time
  7. Add a debugger above the render line and step step step to see what's happening inside the gem (mismatch might be somewhere in make_and_send_pdf's render(render_opts) (which is Rails's render)

I hope this helps some. Let me know if you are still having trouble, maybe send me an email and we can screenshare pair on it.

srbong commented 1 year ago

@unixmonkey

Thanks for the pointing me in the right direction. I was able to get it working by:


For anyone else who is struggling with this:

WORKED IN RAILS 6.1 BUT NOT RAILS 7:

render pdf: filename,
               disposition: 'attachment',
               layout: 'application.html',
               template: 'examples/index.html',
               print_media_type: true

WORKS IN RAILS 7:

render pdf: filename,
               disposition: 'attachment',
               layout: 'application',
               template: 'examples/index',
               formats: :html,
               print_media_type: true
dvodvo commented 9 months ago

Alas, I have another twist on this type of error with Rails 7.0.8
I am posting this here because I am making an assumption that they might be related.

when running in localhost, the PDF renders with the desired precompiled stylesheet.

    <%= stylesheet_link_tag wicked_pdf_asset_base64("initialise") %>
    <%= stylesheet_link_tag wicked_pdf_asset_base64("foundation") %>
    <%= stylesheet_link_tag wicked_pdf_asset_base64("zapp_pdf") %>

On the server, the styles were amiss, so I tested by adding a static stylesheet which renders in a browser if called per se . Also, the images in the same public/assets directory are rendered in the generated PDF (confirming no issue with static paths. The stylesheets would render only upon setting the template with:

    <%= wicked_pdf_stylesheet_link_tag "https://sandbox.example.com/assets/initialise.css" %>
    <%= wicked_pdf_stylesheet_link_tag "https://sandbox.example.com/assets/foundation.css" %>
    <%= wicked_pdf_stylesheet_link_tag "https://sandbox.example.com/assets/zapp_pdf.css" %>

While the issue is overcome, this does throw some shade to the suggestion regarding the helpers <%= stylesheet_link_tag wicked_pdf_asset_base64("pdf") %>

Relevant info: • localhost runinng on OS X 12.3 • server in development mode running Ubuntu 22.04

assets.rb precompiles (at least locally) with:

Rails.application.config.assets.precompile += %w( initialise.css foundation.css zapp.css zapp_pdf.css )

The controller action calls for the PDF rendering as follows.

    respond_to do |format|
      format.html
      format.pdf do
        render pdf: 
          "#{@individual.name_last}_#{@individual.name_first}_info",
           layout: 'pdf', 
           encoding: 'utf8',
           header: { right: '[page] of [topage]' },
           page_size: 'A4'
      end
    end
mathieujobin commented 9 months ago

For us, the solution was to rename the view files. many were like action_pdf.haml we made them action.pdf.haml

asecondwill commented 6 months ago

For me I had to change the template name from show.pdf.erb to showpdf.pdf.erb or it just kept trying to use the show.html.erb template, it had worked find before update to rails7. I tried the above fixes. This is what worked in the end:

  pdf = WickedPdf.new.pdf_from_string(
      render_to_string(pdf: 'PropertyReport', template: '/reports/showpdf', layout: 'pdf')
    )
startbotbot commented 5 months ago

After trying the above solutions i still got "Template is missing", this my code:

  def index
    @projects = Project.all
    # print pdf file usgin the wicked_pdf gem
    respond_to do |format|
     format.html
     format.pdf do
      render pdf: 'test_wickedpdf',
              template: 'projects/index.html.erb',
              formats: [:html],
              disposition: :inline,
              layout: 'pdf'
     end
    end
  end
yshmarov commented 5 months ago

After trying the above solutions i still got "Template is missing", this my code:

  def index
    @projects = Project.all
    # print pdf file usgin the wicked_pdf gem
    respond_to do |format|
     format.html
     format.pdf do
      render pdf: 'test_wickedpdf',
              template: 'projects/index.html.erb',
              formats: [:html],
              disposition: :inline,
              layout: 'pdf'
     end
    end
  end

try this:

-               template: 'projects/index.html.erb',
+              template: 'projects/index',
startbotbot commented 5 months ago

thanks for your answer, now i got: no implicit conversion of Array into String

fguillen commented 3 months ago

In my case the problem was in the layout declarations like in here:

layout "admin/base"

Now I have to include the layouts root folder

I changed it to:

layout "layouts/admin/base"

And it worked

pramodshinde commented 2 months ago

If anyone bumps on this again,

I had the same issue there are the following ways to resolve this

  1. Without layouts and formats arguments render pdf: 'quotation_id1', template: 'admin/quotations/show', disposition: 'inline' Note: This will work only if your template name isshow.pdf.haml`

  2. With layouts and formats arguments render pdf: 'quotation_id1', template: 'admin/quotations/show', formats: [:html], disposition: 'inline', layout: 'pdf' Note: formats: [:html] and layout: 'pdf' will work only if your template name is show.html.haml

PDF could not be generated! (RuntimeError)
Command Error: pid 53827 exit 1
/Users/xxxxx/.rvm/rubies/ruby-3.1.2/lib/ruby/3.1.0/bundler/definition.rb:481:in `materialize': Could not find pg-1.4.3
....
....
in any of the sources (Bundler::GemNotFound)

To resolve this, I found this link (Thanks @unixmonkey)

Default gem is not loading dist specific binary( I think...true?)

Extracting correct binaries from gem wkhtmltopdf-binary to bin worked for me

c.exe_path = Rails.env.production? ? Rails.root.join('bin/wkhtmltopdf_ubuntu_22.04_amd64').to_s : Rails.root.join('bin/wkhtmltopdf_macos_cocoa').to_s

I am using

Rails 7.0.3.1
3.1.2 :001
gem 'wicked_pdf', '~>2.8.0'
gem 'wkhtmltopdf-binary', '~>0.12.6.7'
unixmonkey commented 2 months ago

@pramodshinde

Default gem is not loading dist specific binary( I think...true?)

I think this is a symptom of your server's shell user not having the same ruby environment as your app. When you install wkhtmltopdf-binary, it adds a ruby file as a binstub in the gem, so when you generate a pdf, it runs that ruby script to figure out which binary to use, but if that script is run as a different user than your web app, it might not have the same bundler isolation and gemsets. Hence, why it is complaining about the pg gem, which is in your app's bundler environment, but not in the shell running wkhtmltopdf, but somehow that shell also knows about your Gemfile and what's in it.

I sometimes wonder if that binscript should be rewritten in bash for this reason, if that's even possible.