Double rendering error in Rails while using wicked pdf gem - ruby-on-rails

In my rails app, I am creating an API that accepts order details from other devices and generates pdf which is then uploaded to the AWS.I am using wicked_pdf gem to generate the pdf and aws-sdk to upload data to Aws. The controller code is as follows.
def order_invoice
response = Hash.new
result = Hash.new
if params[:order] && params[:order][:txnid] &&
params[:no_of_copies] && params[:order][:total_amount]!= 0
#order = params[:order]
...
#no_of_copies = params[:no_of_copies]
invoice = create_pdf
response['result'] = invoice
response.merge! ApiStatusList::OK
else
response.merge! ApiStatusList::INVALID_REQUEST
end
render :json => response
end
def create_pdf
pdf = WickedPdf.new.pdf_from_string(
render_to_string(template: 'invoices/generate_invoice.pdf.erb'))
send_data(pdf, filename: params[:order][:txnid] + ".pdf" ,
type: 'application/pdf',
disposition: 'attachment', print_media_type: true)
save_path = Rails.root.join('pdfs', #order['txnid'] + ".pdf")
File.open(save_path, 'wb') do |file|
file << pdf
filename = #order['txnid'] + ".pdf"
end
file_name = #order['txnid'] + ".pdf"
upload = Invoice.upload(save_path, file_name)
end
While generating and uploading the pdf I get the following error
AbstractController::DoubleRenderError in Api::V0::InvoiceApiController#order_invoice
Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".
I need to give the link of the uploaded pdf as response. I know the error is because of using two renders here. However I dont know how to overcome the error. Can anyone help me to tweak and correct the code. Newbie in rails and api's.

This is because you render repsonse 2 times:
via send_data in #create_pdf
via render :json => response in action
UPD:
After discussion, we came to this - you don't need content of the file in your response, only link to AWS.
So, to fix this just remove your send_file call:
def create_pdf
# render_to_string doesn`t mean "render response",
# so it will not end up "double render"
pdf = WickedPdf.new.pdf_from_string(
render_to_string(template: 'invoices/generate_invoice.pdf.erb'))
# send_file renders response to user, which you don't need
# this was source of "double render" issue
# so we can just remove it
save_path = Rails.root.join('pdfs', #order['txnid'] + ".pdf")
File.open(save_path, 'wb') do |file|
file << pdf
filename = #order['txnid'] + ".pdf"
end
file_name = #order['txnid'] + ".pdf"
upload = Invoice.upload(save_path, file_name)
end

Related

download pdf from S3 through active admin on rails

I have a PDF uploaded in order_items table through paperclip gem. PDF is uploaded successfully and I can see the file uploaded by visiting the S3 url generated.
My problem is, when I am downloading file on active admin it is giving me error:
ActionController::MissingFile
Cannot read file
My member_action in active admin is:
member_action :art_proof, method: :get do
#order = resource
#order_item = #order.order_items.where(id: params[:item_id]).first
#uniform = #order_item.uniform
#stock = #order_item.stock
if #order_item.decoration_preview.url
send_file #order_item.decoration_preview.url,
filename: #order_item.decoration_preview_file_name,
type: #order_item.decoration_preview_content_type
render :nothing => true
else
render layout: false
end
end
I am trying to download file through send_file method. Any idea why this is happening?
I don't think you can use send_file with an S3 URL. Instead I pre-sign the URL and redirect_to the URL. Something like:
aws_resource = Aws::S3::Resource.new(credentials: credentials)
presigner = Aws::S3::Presigner.new(client: aws_resource.client)
redirect_to presigner.presigned_url(:get_object, bucket: bucket_name, key: file.key)

Zip Excel sheet generated through gem axlsx rails

I'm facing an issue of how to zip the excel sheet generated through gem 'axlsx_rails'. For example:
class SampleController < ApplicationController::Base
def export
if params[:zip]
xxxx
else
render xlsx: 'export', filename: filename, disposition: 'attachment'
end
end
end
In the above example, right now the end user is able to download the excel sheet but if the end user requests a zip file of excel sheet, how can we do that. Because of code in 'else' block the end user is able to download the excel sheet. What I have to do if the user wants the excelsheet to be zipped before download. If you need any further info, plz let me know. Thanks
This is untested code, but try using Zip::ZipOutputStream:
def export
if params[:zip]
compressed_filestream = Zip::ZipOutputStream.write_buffer do |zos|
content = render_to_string xlsx: 'export', filename: filename
zos.put_next_entry(filename)
zos.print content
end
compressed_filestream.rewind
send_data compressed_filestream.read, filename: 'export.zip', type: 'application/zip'
else
render xlsx: 'export', filename: filename, disposition: 'attachment'
end
end
If it doesn't work, create an issue on Github, and after we get it working we can add it to the documentation.

prawn rails download on open

I use prawn-rails.
I have a show.pdf.prawn view.
I would like to have an action to download this pdf.
I tried the following:
def download
send_data(
show,
filename: "#{custom_name}.pdf",
type: 'application/pdf'
)
end
What it does, is download something called #{custom_name}.pdf but I m unable to open it (falied to load PDF document).
Having it changed to
def download
send_file(
show,
filename: "#{custom_name}.pdf",
type: 'application/pdf'
)
end
I am getting
no implicit conversion of true into String
Please advice.
Should work:
send_data render_to_string("show"), filename: "#{custom_name}.pdf",
type: 'application/pdf'
Also you can use prawnto_2 library:
gem "prawnto_2", require: "prawnto"
and then simply render in the controller action:
def show
respond_to do |format|
format.pdf {
prawnto inline: false,
filename: "#{custom_name}.pdf",
prawn: {} # prawn settings here
}
end
end
But I'm not sure how this library is currently maintained, however still works with Rails 4.2.x.
How about:
def download
response.headers['Content-Disposition'] = 'attachment; filename="' + custom_name + '.pdf"'
render :show, mime_type: Mime::Type["application/pdf"]
end

How to export a HTML file in Rails?

I am trying to export links that are in my database into a HTML Netscape Bookmark File using Markio.
This following Ruby code is from Markio. I'm not sure how to get it to work with Rails so I can export links from my database to a file the user can download.
builder = Markio::Builder.new
builder.bookmarks << Markio::Bookmark.create({
:title => "Google",
:href => "http://google.com"
})
file_contents = builder.build_string
File.open('/path/to/bookmarks.html', 'w') { |f| f.write file_contents }
This is what I have so far in my Rails app. I am most likely going about it completely wrong because I only know how to do it with CSV and Excel. Each Link in my Rails database has a title and a url.
If I navigate to links/export in my browser it should download a file but I get the error "uninitialized constant Markio::Link".
This is my Links controller:
def export
#links = Link.all
respond_to do |format|
format.html { send_data #links.to_csv }
end
end
This is my Links model:
def self.to_csv(options = {})
builder = Markio::Builder.new
builder.bookmarks << Markio::Link.create({
:title => title,
:href => url
})
file_contents = builder.build_string
File.open('/path/to/bookmarks.html', 'w') { |f| f.write
file_contents }
end
Shouldn't Markio::Link be Markio::Bookmark? I don't see a Link object in their API.

How to save generated pdf in server in rails

Currently I am generating a pdf using prawn gem of rails. pdf is generated when user hit on this action
def print_pdf
#user = User.find(params[:id])
#details = #user.details_data
respond_to do |format|
format.pdf do
pdf = PrintDetailsPdf.new(#user, view_context, #details)
send_data pdf.render, filename: "#{#user.id}.pdf",
type: 'application/pdf',
disposition: 'inline'
end
end
end
In above action, I generate the pdf and show it in browser and it works perfectly. But I want to show the pdf in browser and also save the pdf at server in public/user_details directory. How can I do that?
There are some good gems that help in file uploading and saving. Here is a list of these gems. Paperclip and Carrierwave are the most popular options.
You could also implement it from scratch. Rails has built-in helpers which make it easy to roll your own solution.
pdf_content = *Content you want to save in the file*
File.open(Rails.root.join('public', 'user_details', filename), 'wb') do |file|
file.write(pdf_content.read)
end
It depends on the complexity of what you want to achieve, but this is totally sufficient for easy file saving tasks. Go here to find more information.
You could do this
pdf_string = render_to_string :template => 'template', :layout => false
File.open("public/userfiles/example.pdf", 'wb') { |
f| f.write(pdf_string) }
end
Render the template to string and then create a file and write that pdf to it..
This should help

Resources