I have an uploader (internal use only) that will upload an HTML document to a binary column of a table in my client-facing website. The client facing site has an index that allows the user to view the page as a normal website (using send_data h_t.html_code, :type => "html", :disposition => "inline"). I also want to give the user the ability to download a PDF of the page. For that I'm using wicked_pdf.
The entire problem seems to stem from the fact that the data is stored in the database. As strange as it sounds, it is vital to business operations that I get formatting exact. The issue is I can't see any image, and the stylesheets/style tags don't have any effect.
What I've tried-
Gsub-
def show
html = HtmlTranscript.find(params[:id])
html_code = html.html_code.gsub('<img src="/images/bwTranscriptLogo.gif" alt="Logo">','<%= wicked_pdf_image_tag "bwTranscriptLogo.gif" %>')
html_code = html_code.gsub('<link rel="StyleSheet" href="" type="text/css">','<%= wicked_pdf_stylesheet_link_tag "transcripts.css" %>')
transcript = WickedPdf.new.pdf_from_string(html_code)
respond_to do |format|
format.html do
send_data transcript, :type => "pdf", :disposition => "attachment"
end
##### i never could get this part figured out, so if you have a fix for this...
# format.pdf do
# render :pdf => "transcript_for_#{#html.created_at}", :template => "html_transcripts/show.html.erb", :layout => false
# end
end
end
Using a template-
#Controller (above, modified)
html = HtmlTranscript.find(params[:id])
#html_code = html.html_code.gsub('<img src="/images/bwTranscriptLogo.gif" alt="Logo">','<%= wicked_pdf_image_tag "bwTranscriptLogo.gif" %>')
#html_code = #html_code.gsub('<link rel="StyleSheet" href="" type="text/css">','<%= wicked_pdf_stylesheet_link_tag "transcripts.css" %>')
transcript = WickedPdf.new.pdf_from_string(render_to_string(:template => "html_transcripts/show.html.erb", :layout => false))
#view
<!-- tried with stylesheet & image link tags, with wicked_pdf stylesheet & image link tags, with html style & img tags, etc -->
<%= raw(#html_code) %>
And both will generate a transcript- but neither will have style OR image.
Creating an initializer-
module WickedPdfHelper
def wicked_pdf_stylesheet_link_tag(*sources)
sources.collect { |source|
"<style type='text/css'>#{Rails.application.assets.find_asset("#{source}.css")}</style>"
}.join("\n").gsub(/url\(['"](.+)['"]\)(.+)/,%[url("#{wicked_pdf_image_location("\\1")}")\\2]).html_safe
end
def wicked_pdf_image_tag(img, options={})
image_tag wicked_pdf_image_location(img), options
end
def wicked_pdf_image_location(img)
"file://#{Rails.root.join('app', 'assets', 'images', img)}"
end
def wicked_pdf_javascript_src_tag(source)
"<script type='text/javascript'>#{Rails.application.assets.find_asset("#{source}.js").body}</script>"
end
def wicked_pdf_javascript_include_tag(*sources)
sources.collect{ |source| wicked_pdf_javascript_src_tag(source) }.join("\n").html_safe
end
end
did absolutely nothing, and I have no idea what to try next.
As a side note, the code to view the HTML version of the transcript is as follows:
def transcript_data
h_t = HtmlTranscript.find(params[:id])
send_data h_t.html_code, :type => "html", :disposition => "inline"
end
It requires no view, as the html data is stored in the database, but I get image, style, etc. Everything works with the HTML version- just not the PDF.
I'm on ruby 1.8.7 with rails 3.0.20.
Solved-
As it turns out, there was more than one issue at hand.
1- Installation of wkhtmltopdf for Ubuntu via $apt-get install does not quite do the trick for what I wanted...
see http://rubykitchen.in/blog/2013/03/17/pdf-generation-with-rails
(there may have also been an issue with having not previously run sudo apt-get install openssl build-essential xorg libssl-dev libxrender-dev, as when I did, it installed a number of components I did not previously have.)
2- The HTML files I had uploaded contained image & style code that was breaking the formatting. I fixed it with this...
def rm_by_line(which = 0, line1 = 0, line2 = 0)
h_t = HtmlTranscript.find(which)
line_by_line = h_t.html_code.split('
')
for i in line1..line2
line_by_line[i] = ''
end
line_by_line = line_by_line.join('
').strip
return line_by_line
end
Then, all I had to do was pass which lines I wanted to remove.
(I had to split the parens with a carriage return because '\n' didn't function properly when calling 'raw' on the returned string.)
3- wicked_pdf_stylesheet_link_tag and wicked_pdf_image_tag were undefined. I had to inline the style formatting I wanted into a layout I created (turns out wicked_pdf_stylesheet_link_tag used asset pipeline wich my ruby/rails did not implement, which also means I had to get rid of the javascript helpers) and created a helper for wicked_pdf_image_tag, making a switch in the layout for which image tag (image_tag or wicked_pdf_image_tag) to be used.
4- I needed both a .html.erb & a .pdf.erb for my templates, so I made both.
5- Got rid of WickedPdf.new.pdf_from_string in favor of linking to either html or pdf by using :format => 'html' or :format => 'pdf' in the link_to tag.
I'm having some issue figuring out how to handle success on my entries form using rails 3 ujs ajax.
If there are errors, I have a create.js.erb that will alert(j(#entry.errors.full_messages), and this works. But if there are no errors, the form doesn't redirect (because I'm rendering in a dialog) and I'd like the js to alert("success") and close the dialog. (using fancybox 2).
Can you give me some pointers working with rails 3 ujs and ajax?
An approach is to identify and handle the error at controller level instead of view.
def create
#entry = something
if #entry.save
#notice = "Success message!"
respond_to :js # render default create.js.erb
else
respond_to :js { render 'create_error.js.erb' }
end
end
// create.js.erb
$("#dialog").close();
alert("<%= #notice %>">;
// create_error.js.erb
alert(j(#entry.errors.full_messages);
I have a controller where I set layout to false:
class SplashController < ApplicationController
layout false
def index
end
end
But when I load this page there is no css whatsoever - I assume this has to do with how rails handles layout false - but my current knowledge of rails leaves me lost.
How do I not render a layout, but still load all the other assets (css, js, etc. . .) that would typically load if I were to load a layout? (*Note that the layout file has no specific reference to any of these assets)
By default, if you use the :text option, the text is rendered without using the current layout. If you want Rails to put the text into the current layout, you need to add the :layout => true option.
As you need only the information to be displayed, I suggest to use :text to render.
You can send plain text – with no markup at all – back to the browser by using the :text option to render:
render :text => "OK"
NOTE: Rendering pure text is most useful when you’re responding to AJAX or web service requests that are expecting something other than proper HTML.
UPDATE:
Also if you want that assets should be shown but still layout should be false then you have to render layout to false after making the assets available. This means you make some view, then define your required css and js files there and then call that view from controller and then set layout to false.
Setting the layout to false after view will show the css and js stuff but still keep the layout to false.
But setting the layout to false before showing the view that contains css and js will not include assets at all.
The other alternative of the above will work also:
css : <%= eval("render :partial => 'myurl/blah', :formats=> [:css], :layout => false").dump.html_safe %>
You see that how partial view that contains your assets like :css is getting called while layout is false.
The edit view for one of my models contains tabs that utilize anchors in the url to switch between settings such as model/1/edit#tab1 and model/1/edit#tab2. Is there a way to redirect to these anchors after submitting the edit form but failing to save due to errors? My current code is below:
def update
#user = Product.new(params[:user])
if #user.save
flash[:success] = "Your user has been created"
redirect_to #user
else
render 'edit' //want to render here with an anchor
end
end
I would like to store the url containing the anchor before form submit and then re-render the form with the same anchor while rendering error messages. Any ideas?
Best way was to use jquery cookie to save last opened tab and then set default tab using saved cookie.
I am storing customer-specific partials on S3. When I render the value of the S3 object, it renders as text. How can I render it so that it appears within my main layout?
Looks like I just need to:
render :text => myTextFromS3, :layout => true
And it works!
Update: Since 2013 rails changed
There is 3 different ways:
render html: '<strong>HTML String</strong>' # render with `text/html` MIME type
render plain: 'plain text' # render with `text/plain` MIME type
render body: 'raw body' # render raw content, does not set content type, inherits
# default content type, which currently is `text/html`
Source https://github.com/rails/rails/issues/12374