How to show dynamic maps in PDF using wicked_pdf - ruby-on-rails-3

I want to show world region wise map inside my PDF document. I had generated map using some jquery library but not bale to export same map inside PDF document generated through wicked_pdf.

Here is code that works for me (you can attach ?d=1 see HTML version of PDF):
def index
render :pdf => "pdf_with_map",
:disposition => "attachment",
:show_as_html => (params[:d] == "1"),
:layout => "pdf",
:orientation => 'Landscape'
end
And here is pdf layout:
!!!
%html
%head{:xmlns => 'http://www.w3.org/1999/xhtml', :lang => 'en', 'xml:lang' => 'en'}
%meta{:charset => "utf-8"}
%title PDF
= wicked_pdf_stylesheet_link_tag 'pdf'
= wicked_pdf_javascript_include_tag 'jquery', 'jquery-jvectormap', 'jquery-jvectormap-world-en', 'regionVectorMap'
= csrf_meta_tags
%body
#content
= yield
When you use debug you will see that the helpers are embeding JavasSript into HTML. Map did not work for me if jquery was in gem, I moved jquery into my app/assets and so that the wicked_pdf_javascript_include_tag can find the source ;-)

Related

Allowing User to Download File from S3 Storage

Right now I am using Amazon S3 and Paperclip which is allowing my users to upload an image that is associated with the event they are creating. My ultimate goal is since others can view this event, to be able to click on the image and have it prompt a SAVE TO their computer. As of now, clicking the link will open the image in a browser window. I rather have it ask for them to download instead. All images only saved on S3, not local. Need to hide exposed s3 url as well if possible or camouflage it
Here is my current setup
Index.html
<%= link_to 'Download Creative', event.creative.url, class: "btn btn-info" %>
Event.rb
has_attached_file :creative,
:styles => { :thumb => "150x150", :custcreative => "250x75" },
:path => ":attachment/:id/:style.:extension",
:s3_domain_url => "******.s3.amazonaws.com",
:storage => :s3,
:s3_credentials => Rails.root.join("config/s3.yml"),
:bucket => '*****',
:s3_permissions => :public_read,
:s3_protocol => "http",
:convert_options => { :all => "-auto-orient" },
:encode => 'utf8'
Hoping someone can help me out.
To avoid extra load to your app (saving dyno's time in Heroku), I would rather do something like this: add this method to your model with the attachment:
def download_url(style_name=:original)
creative.s3_bucket.objects[creative.s3_object(style_name).key].url_for(:read,
:secure => true,
     :expires => 24*3600,  # 24 hours
     :response_content_disposition => "attachment; filename='#{creative_file_name}'").to_s
end
And then use it in your views/controllers like this:
<%= link_to 'Download Creative', event.download_url, class: "btn btn-info" %>
To make this work, I've just added a new action in the controller, so in your case it could be:
#routes
resources :events do
member { get :download }
end
#index
<%= link_to 'Download Creative', download_event_path(event), class: "btn btn-info" %>
#events_controller
def download
data = open(event.creative_url)
send_data data.read, :type => data.content_type, :x_sendfile => true
end
EDIT:
the correct solution for download controller action can be found here (I've updated the code above): Force a link to download an MP3 rather than play it?
Now in aws-sdk v2, there is a method :presigned_url defined in Aws::S3::Object, you can use this method to construct the direct download url for a s3 object:
s3 = Aws::S3::Resource.new
# YOUR-OBJECT-KEY should be the relative path of the object like 'uploads/user/logo/123/pic.png'
obj = s3.bucket('YOUR-BUCKET-NAME').object('YOUR-OBJECT-KEY')
url = obj.presigned_url(:get, expires_in: 3600, response_content_disposition: "attachment; filename='FILENAME'")
then in your views, just use:
= link_to 'download', url
event = Event.find(params[:id])
data = open(event.creative.url)
send_data data.read, :type => data.content_type, :x_sendfile => true, :url_based_filename => true
end
You need to set the "Content-Disposition" to "attachment" in your HTTP response header. I'm not a Rails developer - so just Google it and you'll see plenty of examples - but it probably looks something like this:
:content_disposition => "attachment"
or
...
:disposition => "attachment"

customize kaminari pagination template

I'm having difficulty customizing the default kaminari template.
I've used the generator to create kaminari template files. In kaminari/paginator.html.haml:
= paginator.render do
%nav.pagination
All I want to do is access the actionview helpers within this, like link_to, or render. I've searched the source code and I can't find any incline of the helper being passed to this render method.
Essentially, being able to do this:
= paginator.render do
%nav.pagination
= render :partial => 'custom links'
= link_to "custom link", custom_path
..would solve my problems.
I didn't get a satisfactory answer, and so I'll submit my own solution.
Helpers cannot be used in the paginator.render block.
So, first I generate kaminari custom template files:
rails g kaminari:views default -e haml
Create a new file kaminari/custom.html.haml with the contents:
#pagination
= paginate custom
= render :partial => "kaminari/custom_view_file"
Replace kaminari paginator helper (paginate #results) in your view file with:
= render :partial => "kaminari/custom", :object => #results
You should be able to do something like this:
# /app/views/kaminari/_paginator.html.erb
= paginator.render do
%nav.pagination
= render :partial => 'shared/custom'
= link_to "custom link", custom_path
Basically, you need to provide the full path of the partial as it probably does not reside in the same directory.
EDIT:
I think Kaminari does not import rails view helpers in the paginate.render block in _paginator.html.erb.
To customize the output generated by paginator, you should instead
1. customize the _next_page.erb.html and so on where you can use rails helpers. I don't know why it is so though.
2. If you want to display some common html as a part of paginator, I suggest you put it in layout instead. Paginator is about navigation of pages.
For example, this is the _prev_page.html.erb:
<span class="prev">
<%= link_to "google", "www.google.com" %>
<%# link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote %>
</span>
I just commented out the old code and used a custom link.
Just met the same problem.
My solution:
= paginator.render do
%nav.pagination
= render :partial => 'custom links'
= #template.link_to "custom link", custom_path
As partial rendering occurs in scope of Paginator, there is possibility to use its instance variable, pointing to template (see https://github.com/amatsuda/kaminari/blob/master/lib/kaminari/helpers/paginator.rb)
Little hacky, but works.

Is Greyscale function of Wicked_PDF functional?

In my project I am trying to print a PDF in Greyscale with a couple of images and text from HTML using the wicked_PDF. The Gem provides a function for the same, but it doesn't seem to be working.
Here is my code:
render :pdf => "MyObject",
:wkhtmltopdf => '/usr/local/bin/wkhtmltopdf',
:template => '/widgets/pdf/show_myObject.erb',
:page_size => 'A4',
:header => { :html => { :template => "/widgets/pdf/myObject_header.erb" }},
:footer => { :html => { :template => "/widgets/pdf/myObject_footer.erb" }, :line => true },
:margin => { :top => 0, :left => 3, :right => 3 },
:greyscale => true
I am passing the images as background. But it renders in color. Am I missing something? Why is wicked_PDF gem unable to process greyscale function as expected?
Their documentation did not have any help regarding this.
Turns out the wkhtmltopdf --grayscale option was incorrectly coded in wicked_pdf as --greyscale
(swap the 'e' for an 'a').
I've pushed a fix, and cut a new version of the gem (0.7.9) for this. Thanks for pointing it out!
:grayscale => true
Now works as intended.

Rails 3 ActionMailer and Wicked_PDF

I'm trying to generate emails with rendered PDF attachements using ActionMailer and wicked_pdf.
On my site, I'm using already both wicked_pdf and actionmailer separately. I can use wicked_pdf to serve up a pdf in the web app, and can use ActionMailer to send mail, but I'm having trouble attaching rendered pdf content to an ActionMailer (edited for content):
class UserMailer < ActionMailer::Base
default :from => "webadmin#mydomain.com"
def generate_pdf(invoice)
render :pdf => "test.pdf",
:template => 'invoices/show.pdf.erb',
:layout => 'pdf.html'
end
def email_invoice(invoice)
#invoice = invoice
attachments["invoice.pdf"] = {:mime_type => 'application/pdf',
:encoding => 'Base64',
:content => generate_pdf(#invoice)}
mail :subject => "Your Invoice", :to => invoice.customer.email
end
end
Using Railscasts 206 (Action Mailer in Rails 3) as a guide, I can send email with my desired rich content, only if I don't try to add my rendered attachment.
If I try to add the attachment (as shown above), I get an attachement of what looks to be the right size, only the name of the attachment doesn't come across as expected, nor is it readable as a pdf. In addition to that, the content of my email is missing...
Does anyone have any experience using ActionMailer while rendering the PDF on the fly in Rails 3.0?
Thanks in advance!
--Dan
WickedPDF can render to a file just fine to attach to an email or save to the filesystem.
Your method above won't work for you because generate_pdf is a method on the mailer, that returns a mail object (not the PDF you wanted)
Also, there is a bug in ActionMailer that causes the message to be malformed if you try to call render in the method itself
http://chopmode.wordpress.com/2011/03/25/render_to_string-causes-subsequent-mail-rendering-to-fail/
https://rails.lighthouseapp.com/projects/8994/tickets/6623-render_to_string-in-mailer-causes-subsequent-render-to-fail
There are 2 ways you can make this work,
The first is to use the hack described in the first article above:
def email_invoice(invoice)
#invoice = invoice
attachments["invoice.pdf"] = WickedPdf.new.pdf_from_string(
render_to_string(:pdf => "invoice",:template => 'documents/show.pdf.erb')
)
self.instance_variable_set(:#lookup_context, nil)
mail :subject => "Your Invoice", :to => invoice.customer.email
end
Or, you can set the attachment in a block like so:
def email_invoice(invoice)
#invoice = invoice
mail(:subject => 'Your Invoice', :to => invoice.customer.email) do |format|
format.text
format.pdf do
attachments['invoice.pdf'] = WickedPdf.new.pdf_from_string(
render_to_string(:pdf => "invoice",:template => 'documents/show.pdf.erb')
)
end
end
end
I used of Unixmonkey's solutions above, but then when I upgraded to rails 3.1.rc4 setting the #lookup_context instance variable no longer worked. Perhaps there's another way to achieve the same clearing of the lookup context, but for now, setting the attachment in the mail block works fine like so:
def results_email(participant, program)
mail(:to => participant.email,
:subject => "my subject") do |format|
format.text
format.html
format.pdf do
attachments['trust_quotient_results.pdf'] = WickedPdf.new.pdf_from_string(
render_to_string :pdf => "results",
:template => '/test_sessions/results.pdf.erb',
:layout => 'pdf.html')
end
end
end
Heres' how I fixed this issue:
Removed wicked_pdf
Installed prawn (https://github.com/sandal/prawn/wiki/Using-Prawn-in-Rails)
While Prawn is/was a bit more cumbersome in laying out a document, it can easily sling around mail attachments...
Better to use PDFKit, for example:
class ReportMailer < ApplicationMailer
def report(users:, amounts:)
#users = users
#amounts = amounts
attachments["proveedores.pdf"] = PDFKit.new(
render_to_string(
pdf: 'bcra',
template: 'reports/users.html.haml',
layout: false,
locals: { users: #users }
)
).to_pdf
mail subject: "Report - #{Date.today}"
end
end

What's the alternative of :before & :after of rails 2.3.* in Rails 3?

I am using remote form in Rails 3. It works fine but I want to show / hide spinner during ajax request.
In rails 2.3.* we use :before & :after in remote form to show/hide spinner
What should I do in Rails 3, as remote form of Rails 3 doesn't contain such options.
Here is a working solution I tried:
In my view file, I use :onSubmit to show a spinner:
<% form_for("", #search,
:url => {:action => "search"},
:html => {:id => "search_form",
:onSubmit => "$('search-loader').show();"},
:remote => true) do |f| %>
In my search action, I added one line to hide it:
render :update do |page|
...
page << "$('search-loader').hide();"
end
It works great..!
Well, I'm using jQuery, and I'm doing the following, trying to be unobtrusive:
Add this, right before your </head> tag:
= yield :document_ready
Then in your application_helper.rb:
def document_ready(content)
html = %{ $(function(){#{content}})}
content_for(:document_ready){ javascript_tag(html) }
end
This allows you to load and run javascript once your document is loaded.
On top of the view containing your form add:
- document_ready("hide_button_show_spinner('your_button_id')")
In application.js
function hide_button_show_spinner(element_id) {
$('#'+element_id).bind('click', function() {
$('#'+element_id).after("<img src='/path/to/your/spinner.gif' class='ajax_loader' id='"+element_id+"_ajax_loader' style='display: none'/>")
$('#'+element_id).hide();
$('#'+element_id+'_ajax_loader').show();
});
}
This will hide the button and show the spinner once the button is clicked. You may need to adapt this to your specific case.
You can then show the button and hide the spinner in your javascript response (the .js.erb file that you render from the action called by the ajax request).