After already checking the Rails Gem repository for similar issues as well as Stack Overflow, I couldn't find an answer to my problem.
I'm trying to render a pdf using wicked_pdf within a Rails controller, but the header is not showing up, no matter what I do or which recommended solutions to similar issues I follow.
First and foremost, here is the development console output:
***************WICKED***************
Rendering biddings/show.pdf.html.haml within layouts/pdf
Rendered biddings/show.pdf.html.haml within layouts/pdf (0.7ms)
Rendering biddings/header_pdf.html.haml within layouts/pdf_header
Rendered biddings/header_pdf.html.haml within layouts/pdf_header (1.9ms)
"***************[\"/home/tommy/.rvm/gems/ruby-
2.5.1#igalbids/bin/wkhtmltopdf\", \"-q\", \"--encoding\", \"UTF-8\",
\"--javascript-delay\", \"500\",
\"--disable-internal-links\", \"--disable-external-links\",
\"--orientation\", \"Portrait\", \"--margin-top\",
\"50\", \"--margin-bottom\", \"25\", \"--header-html\",
\"file:////tmp/wicked_header_pdf20180801-27285-b8y5sg.html\",
\"--footer-right\", \"Página [page] de [topage]\",
\"file:////tmp/wicked_pdf20180801-27285-1jfgdd7.html\",
\"/tmp/wicked_pdf_generated_file20180801-27285-1bkrvhx.pdf\"]***************"
Rendering text template
Rendered text template (0.1ms)
Sent data Licitación_2524.pdf (0.6ms)
Completed 200 OK in 2334ms (Views: 0.5ms | ActiveRecord: 64.4ms)
As you can see, both the header layout and its contents are being rendered and processed, however they don't make the final output PDF, and I don't know why! Look:
So, here's my controller code:
class Api::V1::Biddings::PdfBiddingsController < PdfController
# JWT Authentication enforced
before_action :authenticate_user!
# GET /biddings/:id/pdf
def show
#bidding = scoped_collection.find(params[:id])
authorize [:biddings, :pdf, #bidding]
respond_to do |format|
format.pdf do
render(
pdf: "#{Bidding.model_name.human}_#{#bidding.code}",
disposition: "inline",
orientation: "Portrait",
template: 'biddings/show.pdf.html.haml',
header: {
html: {
template: "biddings/header_pdf.html.haml",
handlers: [:haml],
layout: "pdf_header",
formats: [:haml, :html]
}
},
footer: {
html: {
handlers: [:haml],
layout: "pdf",
formats: [:haml, :html],
encoding: 'UTF-8'
},
right: "#{I18n.t('pdf.page')} [page] #{I18n.t('pdf.of')} [topage]"
},
margin: { :top => 50, :bottom => 25},
handlers: [:haml],
layout: "pdf",
javascript_delay: 500,
encoding: 'UTF-8',
show_as_html: false,
disable_internal_links: true,
disable_external_links: true) and return
end
end
end
protected
def self.model
Bidding
end
private
def scoped_collection
policy_scope([:biddings, :pdf, Bidding]).includes(:bidding_type, :client, :payment_condition, :price_list, :real_payment_condition, :sales_man, :user)
end
def records_per_page
params[:per_page] || 10
end
end
Nothing fancy, there you can see all the config options, pretty standard. Needless to say, the footer with the page numbering IS working fine (screenshot too long to show, but trust me). Can't say the same about the header.
Here's the PDF header layout file:
pdf_header.html.haml:
!!! 5
%html
%head
%meta{:content => "text/html; charset=utf-8", "http-equiv" => "content-type"}/
= wicked_pdf_stylesheet_link_tag "bidding_pdf", media: :all
= csrf_meta_tags
%body.pdf
= yield
and here the contents for the header "contents" per se:
header_pdf.html.haml:
Test text
Just plain text. I have a Linux 16.04 x64 OS, wicked_pdf (1.1.0), wkhtmltopdf-binary (0.12.4). How can I debug this?
For anyone who bumps in this, since OP's answer is not too precise, what did the job for me was including a DOCTYPE HTML tag in your header/footer. Went from invisible header (with text that could be found using the search tool), to fully rendered.
For anyone else reaching here... it was a CSS issue. The header was there but "invisible" and no matter what margin I set on the render options it was a CSS issue. After starting the CSS from scratch, the header appeared! I could not debug it with the flag show_as_html: true because header and footer are not rendered in that mode, only the body.
If anyone reads this and happens to be in the same situation, use the search tool in the PDF document to find a word you know that's in the header. If it finds something but it's invisible, then you know you have a CSS problem.
Also don't forget to check if you included in the html of the header the <!DOCTYPE html>. Thanks #joaolell for this.
Another thing to check, is that you have the version with patched qt of the wkhtmltopdf library (0.12.4 and above) that supports header and footer. Previous versions won't
Upgrade wkhtmltopdf binary to at least version "0.12.4 (with patched qt)". I just spent half a day troubleshooting because my version of 0.12.1 did not support header and footer.
Ref: Wicked pdf not rendering header/footer
Related
Working on a PDF and (in both development and production) the PDF will render only the cover page:
https://www.patchvault.org/lodges/456a-powhatan/issues/checklist.pdf
Debug shows the rest of the content, without the cover page:
https://www.patchvault.org/lodges/456a-powhatan/issues/checklist.pdf?debug=true
This intermittently will render fine, or show subsequent pages without images (typical of when it does render), but mostly it just renders the cover. Disabling the cover in the controller action gets the other pages to render as expected. Here's the controller action (I have attachment disabled for development purposes):
def checklist
# PDF Checklist of issues from a lodge
#issues = #issueable.issues.non_event_issues.ordered_issues
#event_issues = #issueable.issues.event_issues.order(issue_number: :asc)
respond_to do |format|
format.html
format.pdf do
render pdf: "#{#issueable.slug}_checklist",
# disposition: 'attachment',
template: 'issues/checklist.pdf.erb',
cover: render_to_string('issues/checklist_cover.pdf.erb'),
dpi: '150',
background: true,
header: {html: {template: 'layouts/_checklist_header'}, spacing: 5 },
footer: {html: {template: 'layouts/_checklist_footer'}, spacing: 0 },
margin: {top: 30, bottom: 20, left: 10, right: 10},
show_as_html: params.key?('debug')
end
end
end
and here's is the output in development to wkhtmltopdf:
"***************[\"/Users/jathayde/Development/Meticulous/Products/patchvault/vendor/cache/ruby/2.4.0/gems/wkhtmltopdf-binary-0.12.3.1/bin/wkhtmltopdf\", \"-q\", \"--dpi\", \"150\", \"--margin-top\", \"30\", \"--margin-bottom\", \"20\", \"--margin-left\", \"10\", \"--margin-right\", \"10\", \"--header-spacing\", \"5\", \"--header-html\", \"file:////var/folders/25/q7y1f5px3xz8bw7sdzcyrz_c0000gn/T/wicked_header_pdf20180312-17436-12xyhl7.html\", \"--footer-spacing\", \"0\", \"--footer-html\", \"file:////var/folders/25/q7y1f5px3xz8bw7sdzcyrz_c0000gn/T/wicked_footer_pdf20180312-17436-eldx10.html\", \"cover\", \"/var/folders/25/q7y1f5px3xz8bw7sdzcyrz_c0000gn/T/wicked_cover_pdf20180312-17436-y1d6wy.html\", \"file:////var/folders/25/q7y1f5px3xz8bw7sdzcyrz_c0000gn/T/wicked_pdf20180312-17436-tr8hae.html\", \"/var/folders/25/q7y1f5px3xz8bw7sdzcyrz_c0000gn/T/wicked_pdf_generated_file20180312-17436-18ftq2q.pdf\"]***************"
The cover is a full HTML page as it wouldn't render styles without being one and calling the CSS file.
Software notes:
Ruby 2.4.0p0
Rails 5.1.5
Patch images are served from S3.
Gems, etc are cached to vendor/cache
The only solution I've found is to remove the Google font call in the cover page, and only load fonts on the inside page template.
According to the GitHub Page for the axlsx gem I should use this syntax to render a xlsx view to a file and attach it:
xlsx = render_to_string handlers: [:axlsx], formats: [:xlsx], template: "users/export", locals: {users: users}
attachments["Users.xlsx"] = {mime_type: Mime::XLSX, content: xlsx}
Here is my mail method:
xlsx = render_to_string(handlers: [:axlsx], formats: [:xlsx], template: 'v1/reports/reportxyz', params: {start_date: '2016-09-12', period: 'weekly'})
attachments["report.xlsx"] = {content: xlsx, mime_type: Mime::XLSX}
mail(to: "my#email.address", subject: "Report", format: "text")
However I get this error when I try and call the mailer method:
ActionView::MissingTemplate: Missing template layouts/mailer with {:locale=>[:en], :formats=>[:xlsx], :variants=>[], :handlers=>[:axlsx]}. Searched in:
* "path/to/project/app/views"
Why is the render_to_string method affecting what the mailer view the mailer is trying to render? locgially I don't have a mailer.xlsx.axlsx file in my app/views/layouts folder but rather the mailer.text.erb I am trying to use as with other emails.
EDIT
I changed the render line to xlsx = render_to_string(template: 'v1/reports/azamara_social', params: {start_date: '2016-09-12', period: 'weekly'})
And now it seems to try and render the xlsx view but of course gets nil:NilClass errors when the xlsx view tries to reference instance variables defined in the reports controller.
Have you tried passing layout: false? What versions of axlsx, axlsx_rails, rails, and rubyzip are you using?
In the end it all came down to moving the controller code into a lib file. This way I call it in the controller to get the data if it needs to be rendered via web-requests as well as via the Mailer method where I recreate the #variables the view template is looking for.
Here is the finished salient parts of the report mailer method:
data = ReportUtils.get_data(args)
xlsx = render_to_string(template: 'path/to/report.xlsx', locals: {:#period => period, :#date_ranges => data[:date_ranges], :#data => data[:data]})
attachments["report.xlsx"] = {content: xlsx, mime_type: Mime::XLSX}
I'm trying to print a PDF of my view by using the `'wicked_pdf' gem. This is the first time I use this gem. I've read the the documentation and googled around and I also found some simular questions here on Stack Overflow But nothing seems to do the trick.
I've validated the binaries ( see edit below) they are working fine, so the problem isn´t there.
I found two strange lines in the terminal when running rails s( See edit at the bottom)
I've been searching for a solution to this for three straight days, and can't figure this out.
Am I missing something here?
the server constantly hangs with that output in the terminal
Rendered pages/partials/_travel_part.html.erb (36.6ms)
Rendered users/show.html.erb within layouts/application (531.7ms)
Rendered layouts/_navbar.html.erb (2.6ms)
Rendered shared/_footer.html.erb (0.8ms)
Completed 200 OK in 1640ms (Views: 1115.4ms | ActiveRecord: 136.0ms)
"***************[\"/usr/local/bin/wkhtmltopdf\", \"-q\", \"file:////var/folders/sm/zwm8cy0x73qb6q1pq22r4bjh0000gn/T/wicked_pdf20160913-35465-hkw9b8.html\", \"/var/folders/sm/zwm8cy0x73qb6q1pq22r4bjh0000gn/T/wicked_pdf_generated_file20160913-35465-10go9dt.pdf\"]***************"
Below is what I have so far.
I want to print views/users/show.html.erb so in the users_controller.rb I have this code in the showmethod
def show
#user = User.find(params[:id])
#users = User.order('created_at DESC').paginate(page: params[:page], per_page: 30)
#paper = current_user.papers.build
#electro = current_user.electros.build
#hwater = current_user.hwaters.build
#cleaning = current_user.cleanings.build
#transport = current_user.transports.build
#papers = current_user.papers
respond_to do |format|
format.html {render layout:'application'}
format.pdf {render pdf:"test",javascript_delay:2000,
layout:'application',template:'users/show.pdf.erb'}
end
end
In the application.html.erbI have this in the head using the wicked pdf helper
<%= wicked_pdf_stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= wicked_pdf_javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= javascript_include_tag "http://www.google.com/jsapi"%>
<%= wicked_pdf_javascript_include_tag 'chartkick'%>
<%= csrf_meta_tags %>
The button in the views/users/show.html.erb is
<%= link_to 'Download Pdf', user_path(current_user, format: :pdf) %>
in the config/initializers/mime_types.rb I have this code
Mime::Type.register "application/pdf", :pdf
in the config/initializers/wicked_pdf.rb I have this code
WickedPdf.config = {
#:wkhtmltopdf => '/usr/local/bin/wkhtmltopdf',
#:layout => "pdf.html",
:exe_path => '/usr/local/bin/wkhtmltopdf'
}
And in the gemfile.rb I have those two gems:
gem 'wicked_pdf', '~> 1.0', '>= 1.0.6'
gem 'wkhtmltopdf-binary-edge'
EDIT*
Ok I've Validated the binaries are working fine by typing this wkhtmltopdf google.com google in the terminal. So my conclusion is that the problem lies somewhere else than in the wkhtmltopdf. But where? I still can't find out...
(AddingWickedPdf) $ wkhtmltopdf google.com google
Loading pages (1/6)
Counting pages (2/6)
Resolving links (4/6)
Loading headers and footers (5/6)
Printing pages (6/6)
Done
(AddingWickedPdf) $
ANOTHER EDIT
I noticed this lines in the terminal when I started my server rails s earlier to night, I don´t know what it means, but I'm sure it has something to do with the App hanging when rendering pdf:
/Users/dadi/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.2.5/lib/action_dispatch/http/mime_type.rb:163: warning: already initialized constant Mime::PDF
/Users/dadi/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack- 4.2.5/lib/action_dispatch/http/mime_type.rb:163: warning: previous definition of PDF was here
It would be so great if someone could take a look at this and guide me to the right path here.
thanks in advance
DH
The answer was originally posted here:
How rails resolve multi-requests at the same time?
Subsequently adapted for this question here (Last answer):
PDFkit hangs when generating a pdf with an image
I am using Wicked pdf gem for creating pdf. It is absolutely working fine on my local. But on production it is giving serious issues. The pdf is generated but in spite of generating a single page it generates 14-15 pages with data like this:
")),this.$.write(e),this.$.close()},find:function(e){return new CKEDITOR.dom.nodeList(this.$.querySelectorAll(e))},findOne:function(e){return(e=this.$.querySelector(e))?new CKEDITOR.dom.element(e):null},_getHtml5ShivFrag:function(){var e=this.getCustomData("html5ShivFrag");return e||
(e=this.$.createDocumentFragment(),CKEDITOR.tools.enableHtml5Elements(e,!0),this.setCustomData("html5ShivFrag",e)),e}}),CKEDITOR.dom.nodeList=function(e){this.$=e},CKEDITOR.dom.nodeList.prototype={count:function(){return this.$.length},getItem:function(e){return
0>e||e>=this.$.length?null:(e=this.$[e])?new CKEDITOR.dom.node(e):null}},CKEDITOR.dom.element=function(e,t){"string"==typeof e&&(e=(t?t.$:document).createElement(e)),CKEDITOR.dom.domObject.call(this,e)},CKEDITOR.dom.element.get=function(e){return(e="string"==typeof e?
document.getElementById(e)||document.getElementsByName(e)[0]:e)&&(e.$?e:new CKEDITOR.dom.element(e))},CKEDITOR.dom.element.prototype=new CKEDITOR.dom.node,CKEDITOR.dom.element.createFromHtml=function(e,t){var n=new CKEDITOR.dom.element("div",t);return
n.setHtml(e),n.getFirst().remove()},CKEDITOR.dom.element.setMarker=function(e,t,n,i){var
r=t.getCustomData("list_marker_id")||t.setCustomData("list_marker_id",CKEDITOR.tools.getNextNumber()).getCustomData("list_marker_id"),o=t.getCustomData("list_marker_names")||t.setCustomData("list_marker_names",{}).getCustomData("list_marker_names");return
e[r]=t,o[n]=1,t.setCustomData(n,i)},CKEDITOR.dom.element.clearAllMarkers=function(e){for(var t in e)CKEDITOR.dom.element.clearMarkers(e,e[t],1)},CKEDITOR.dom.element.clearMarkers=function(e,t,n){var
i,r=t.getCustomData("list_marker_names"),o=t.getCustomData("list_marker_id");for(i in r)t.removeCustomData(i);t.removeCustomData("list_marker_names"),n&&(t.removeCustomData("list_marker_id"),delete e[o])},function(){function e(e,t){return-1<(" "+e+" ").replace(o," ").indexOf(" "+t+"
")}function t(e){var t=!0;return e.$.id||(e.$.id="cke_tmp_"+CKEDITOR.tools.getNextNumber(),t=!1),function(){t||e.removeAttribute("id")}}function n(e,t){var n=CKEDITOR.tools.escapeCss(e.$.id);return"#"+n+" "+t.split(/,\s*/).join(", #"+n+" ")}function i(e){for(var
t=0,n=0,i=a[e].length;i>n;n++)t+=parseInt(this.getComputedStyle(a[e][n])||0,10)||0;return t}var r=document.createElement("_").classList,r="undefined"!=typeof r&&null!==String(r.add).match(/[Native code]/gi),o=/[\n\t\r]/g;CKEDITOR.tools.extend(CKEDITOR.dom.element.prototype,
{type:CKEDITOR.NODE_ELEMENT,addClass:r?function(e){return this.$.classList.add(e),this}:function(t){var n=this.$.className;return n&&(e(n,t)||(n+=" "+t)),this.$.className=n||t,this},removeClass:r?function(e){var t=this.$;retur
The entire 14-15 pages are like this.
This is the method that creates pdf.
def generate_supplier_commission_pdf
#start_date = params[:start_date].to_date.strftime('%d/%m/%Y')
#end_date = params[:end_date].to_date.strftime('%d/%m/%Y')
if params[:sec_filter].present?
sec_filter = true
else
sec_filter = false
end
results = get_report_results_by_type(params[:report_type], #start_date, #end_date, sec_filter)
#results = JSON.parse(results)
#type = params[:report_type].to_i
respond_to do |format|
format.html
format.pdf do
render pdf: "report",
layout: 'pdf_layout',
template: 'reports/generate_supplier_commission_pdf.html.erb',
encoding: 'UTF8',
print_media_type: true,
disposition: 'attachment',
page_size: 'letter',
orientation: 'landscape',
lowquality: 'false',
debug: true
end
end
end
Each and everything like the wkhtml path or anything that can be taken of care of in the code is fine. The only difference I saw is in the logs i.e after this line
***************WICKED***************
Rendered reports/generate_supplier_commission_pdf.html.erb within layouts/pdf_layout (5.2ms)
The following line is not present on server logs.
"***************[\"/usr/bin/wkhtmltopdf\", \"-q\", \"--orientation\", \"landscape\", \"--page-size\", \"letter\", \"--encoding\", \"UTF8\", \"--lowquality\", \"--print-media-type\", \"file:///tmp/wicked_pdf20160903-24256-1v1ay70.html\", \"/tmp/wicked_pdf_generated_file20160903-24256-1da8k68.pdf\"]***************"
I will be really grateful if someone could point out what is going wrong in this case. Thanks in advance.
I managed to resolve this issue by commenting this line in my config/environments/production.rb
# config.assets.js_compressor = :uglifier
and adding this line in it's place:
config.assets.compress = true
I'm using rails 3. In production rails nicely handles exceptions and loads my static 404.html, 500.html etc files from my public directory. However, it loads these files into my layouts/application.html.erb file. I am looking for a way to instruct rails to load these files WITHOUT using my application layout - e.g. just serve the static html file and nothing else. What is the best way to accomplish this?
thanks!
render :file => 'public/404.html', :status => :not_found, :layout => false
For an advanced approach working within the Rails framework. Update your routes file:
get "/404", to: "errors#error_404"
get "/500", to: "errors#error_500"
Add an ErrorsController with:
layout false
def error_404
render status: 404
end
def error_500
render status: 500
end
Then within the app/views/errors/ add your error_404.erb and error_500.erb files along with a snazy image and a search bar.
More info here.