Rails allows you to render an "inline" template, for cases where you have a dynamic template stored in a database:
render :inline => "<p>Hello World</p>", :layout => "application"
Is it possible to use render_to_string in the same way, by passing the complete template string, rather than the filename of a template on disk?
Yes.
Here's an example of converting an html string to a PDF and rendering it:
def show
pdf = WickedPdf.new.pdf_from_string(
'<!doctype html><html><head></head><body><h1>Hello World!</h1></body></html>'
)
respond_to do |format|
format.pdf end
send_data pdf, type: 'application/pdf', disposition: 'inline'
end
end
end
Just make sure it's a complete, fully-formed HTML document, including doctype.
Please let me know if you have any trouble with this.
Thank you! So in my case, if I want to use rails templating to build my HTML document, then I'm guessing I would need to use Rails' render_to_string function first (not to be confused with wicked_pdf's render_to_string function)?
I'm not sure I'm understanding your follow-up question correctly. Maybe an example of what you are trying to do would help?
If you were using Rails' templating, then you'd use WickedPdf's hooks into render(pdf: 'mypdf') or render_to_string(pdf: 'mypdf') with the appropriate options shown in the README, which pretty much do what I just showed you under the hood, after assembling your templates and layout into an HTML tempfile.
So if you had a PostsController#show action, you'd create an app/views/posts/show.pdf.erb file with your html you want to be converted to PDF, and an app/views/layouts/pdf.erb file for the layout, and it'd look something like this:
class PostsController < ApplicationController
def show
@post = Post.find(params[:id])
respond_to do |format|
format.pdf do
render pdf: 'mypdf'
end
end
end
end
Rails' render_to_string works pretty much the same as render, but it outputs a string instead of a response body. If you use render_to_string(pdf: 'mypdf'), you'll get a stringified version of the PDF that can be used to perhaps save the final PDF to your database, or as a file attachment to an email.
Here's an example of how that might be used:
class PostsController < ApplicationController
def email_post
@post = Post.find(params[:id])
pdf = render_to_string('email_post.pdf.erb', layout: 'pdf', pdf: 'mypdf')
current_user.saved_posts.create(pdf_contents: pdf) # save to the db
PostMailer.email_post(current_user, pdf).deliver # email as attachment
redirect_to :show, notice: "Email sent!"
end
end
class PostMailer < ApplicationMailer
def email_post(user, pdf)
attachments['post.pdf'] = pdf
mail to: user.email, subject: "Here's your post!"
end
end
Please let me know if this helps or not.
Thanks. I'm currently using render_to_string to save the PDF to my database鈥擨 don't want to render it to the browser. I'm able to do this with a static template saved on disk, as per your example.
However, I'm working on a multi-tenant application, and would like to use a custom template per-tenant. The template is saved as a string in my database. I want to be able to render that template to a pdf string, using all of Rails' templating + layout functionality.
I think I see.
So you are doing something like:
pdf = render_to_string('email_post.pdf.erb', layout: 'pdf', pdf: 'mypdf')
but you don't want to hard-code layout: 'pdf', as some users might have a different layout.
I don't believe that render allows you to specify an HTML string for the layout; just a string to a template stored in one of Rails' view paths.
If you aren't pre-saving these, you may need to use layout: false, and apply the layout to your HTML string beforehand something like this:
custom_layout = '<!doctype html><html><head></head><body><%= body %></body></html>'
html_contents = render_to_string('email_post.pdf.erb', layout: false)
template = Erubis::Eruby.new(custom_layout)
complete_html_document = template.result(body: html_contents)
pdf_string = WickedPdf.new.pdf_from_string(complete_html_document)
Rails does let you render a raw string as a template, in the manner I indicated in my initial post. See here:
https://guides.rubyonrails.org/layouts_and_rendering.html#using-render-with-inline
But doing the rendering in two phases as you suggest might be the right approach鈥擨'll attempt to see if that works, given that wicked_pdf's version of render_to_string doesn't seem to support the :inline option.
Ah. I think that might fixed if we included the inline option in make_pdf's render_options here.
Additionally, I think you could use Rails's render_to_string, directly like so:
html = render_to_string :inline => "<p>Hello World</p>", :layout => "application"
pdf = WickedPdf.new.pdf_from_string(html)
send_data pdf, filename: 'file_name.pdf'
Do any of these options work for you?
@unixmonkey yes, this approach works for me. Thanks again.
@yowzadave FYI, I've released a new version (1.2.0) of the gem, which also includes support for the inline option.
Let me know if you have any trouble, and I'll reopen this issue.