Ruby on rails, forcing the user to download a tmp file - ruby-on-rails

I've created a file in the tmp directory with the following controller code:
def download
file_path = "#{RAILS_ROOT}/tmp/downloads/xxx.html"
data = render_to_string( :action => :show, :layout => nil )
File.open(file_path, "w"){|f| f << data }
flash[:notice] = "saved to #{file_path}"
end
This creates the file I wanted in the tmp directory, what I want to do is force the user to download that file.
On my local machine, the file is saved to path like:
/Users/xxxx/Documents/Sites/xxxx/Website/htdocs/tmp/downloads/xxxx.html
And on the live server this url will be somthing totally different.
What I was wondering is how do I force the user to download this xxxx.html ?
P.S.
If I put a...
redirect_to file_path
...on the controller it just give's me a route not found.
Cheers.

Take a look at the send_file method. It'd look something like this:
send_file Rails.root.join('tmp', 'downloads', 'xxxxx.html'), :type => 'text/html', :disposition => 'attachment'
:disposition => 'attachment' will force the browser to download the file instead of rendering it. Set it to 'inline' if you want it to load in the browser. If nginx is in front of your Rails app then you will have to modify your environment config (ie. environments/production.rb):
# For nginx:
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'

It's easy to confuse file paths with URLs, but it is an important distinction. What has a URL path of /a/b.txt is actually located in the system path #{Rails.root}/public/a/b.txt so you may need to address this by generating both in tandem.
Here's how you might address that:
def download
base_path = "downloads/xxx.html"
system_path = File.expand_path("public/#{base_path}", Rails.root)
url_path = "/#{base_path}"
File.open(file_path, "w") do |f|
f.puts render_to_string(:action => :show, :layout => nil)
end
flash[:notice] = "saved to #{base_path}"
redirect_to(url_path)
end
You cannot redirect to a resource that is not exposed through your web server, and generally only things in public/ are set this way. You can include additional paths if you configure your server accordingly.
You can also side-step this whole process by simply rendering the response as a downloadable inline attachment, if you prefer:
render(:action => :show, :layout => nil, :content_type=> 'application/octet-stream')

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)

How do i get the url of certificate generated using prawn?

i know how to render it in webapp but i'm supposed to generate pdf through an api call , so i need to send url of the pdf generated instead of the pdf itself ( thats what the mobile developer is asking for ) , is there any way to do it ?
like:
respond_to do |format|
format.pdf do
pdf = CustomCertificatePdf.new(current_user, tutorials)
url = pdf.link
# send_data pdf.render, filename: "custom_certificate_#{current_user.first_name.downcase}_#{current_user.last_name.downcase}.pdf",
# type: "application/pdf",
# disposition: "inline"
render :json => {url: url}
end
end
even your slight hint will be appreciated , thanks :)
save pdf to public folder or upload to another server( S3, google drive, dropbox, ...)
then use that link in api controller
if you save pdf file in public folder, the link should be your host name + relative path with public folder
ex:
file_path = "/webapp/public/pdf/custom_certificate.pdf"
the link should be
http://yourhostname.com/pdf/custom_certificate.pdf
If you need protect your file, you should write another controller to serve it with authentication
This is what i ended up doing
pdf = CustomCertificatePdf.new(current_user, tutorials)
#filename = File.join("custom_certificate_#{current_user.first_name.downcase}_#{current_user.last_name.downcase}.pdf")
pdf.render_file #filename
current_user.cust_cert = File.open("custom_certificate_#{current_user.first_name.downcase}_#{current_user.last_name.downcase}.pdf")
current_user.save!
render :json => {url: "#{current_user.cust_cert}"}
in user model
has_mongoid_attached_file :cust_cert,
:default_url => "",
:path => ':attachment/:id/:cust_cert',
:storage => :s3,
:url => ':s3_domain_url',
:s3_credentials => File.join(Rails.root, 'config', 's3.yml')
validates_attachment_content_type :cust_cert, :content_type => [ 'application/pdf' ], :if => :cust_cert_attached?
def cust_cert_attached?
self.cust_cert.file?
end

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

Rails download file from show action?

I have an uploader which allows you to upload documents. What I want to do is trigger a download for the document when you view its show action. The url would be something like:
/documents/16
This document could be .txt, or .doc.
So far, my show action looks like this:
def show
#document = Document.find(params[:id])
respond_with(#document) do |format|
format.html do
render layout: false, text: #document.name
end
end
end
How would I go about achieving this?
Take a look at the send_data method:
Sends the given binary data to the browser. This method is similar to render :text => data, but also allows you to specify whether the browser should display the response as a file attachment (i.e. in a download dialog) or as inline data. You may also set the content type, the apparent file name, and other things.
So, I think in your case it should be something like this:
def show
#document = Document.find(params[:id])
send_data #document.file.read, filename: #document.name
end
I created a new method in my controller for downloading a file. It looks like this. Stored_File is the name of the archived file and has a field called stored_file which is the name of the file. Using Carrierwave, if a user has the access/permissions to download the file, the URL will display and then send the file to the user using send_file.
Controller
def download
head(:not_found) and return if (stored_file = StoredFile.find_by_id(params[:id])).nil?
case SEND_FILE_METHOD
when :apache then send_file_options[:x_sendfile] = true
when :nginx then head(:x_accel_redirect => path.gsub(Rails.root, ''), :content_type => send_file_options[:type]) and return
end
path = "/#{stored_file.stored_file}"
send_file path, :x_sendfile=>true
end
View
<%= link_to "Download", File.basename(f.stored_file.url) %>
Routes
match ":id/:basename.:extension.download", :controller => "stored_files", :action => "download", :conditions => { :method => :get }

Rails 3.1 Websnap trying to generate a PNG and not getting one

I may be barking up the entire wrong tree here but in case I am not, here's a go.
I am using Websnap to generate a png file of the Show page. When I go to show.png I get a blank white page and no file downloads. It was my expectation that I would get a cute little png downloaded to my machine.
And, I get nada in the log file... not even the debug statements I put in.
Respond to code:
respond_to do |format|
format.html # index.html.erb
format.png {
#html = render :action => "show.html.erb", :layout => "application.html.erb"
snap = WebSnap::Snapper.new("/dashboard/show?application=#{#application}&version=#{#jira_version}", :format => 'png')
send_data snap.to_bytes, :filename => "dashboard.png", :type => "image/png", :disposition => 'inline'}
end
environment.rb
Mime::Type.register "image/png", :png
Turns out Websnap was having an issue finding the wkhtmltoimage executable it put on the system in the first place. I really need to rewrite that Gem.

Resources