Question:
I would like to force link_to to download images and pdfs fetched from S3 instead of opening them in the browser window.
link_to File.basename(asset.attachment.path), asset.attachment_url.to_s
I looked for solutions but the only ones I found are to handle it in the controller using send_file or send_data but these did not work for me. Finally I stumbled upon the solution in Carrierwave sources.
Solution:
This is what works super well. Use 'response-content-disposition' as a parameter to url
link_to File.basename(asset.attachment.path), asset.attachment_url(:query => {"response-content-disposition" => "attachment"}).to_s
Find more options here: https://github.com/carrierwaveuploader/carrierwave/blob/5aec4725a94fca2c161e347f02b930844d6be303/lib/carrierwave/uploader/versions.rb (line 185)
You can default this for all files of a particular uploader by adding a fog_attributes method.
e.g.
# your_uploader.rb
def fog_attributes
{'Content-Disposition' => "attachment"}
end
This works with requests that aren't signed as well!
Related
I uploaded pdf documents on s3 using carrierwave and fog. Is there a way for users to preview content without downloading it?
By the end of the day i realised that i might have not only pdf but other types of files. So in fog.rb i set public to false so it generates uniqe url's
config.fog_public = false
And in my view.html.erb i do a simple link_to so it would open document in a new window without saving it like this:
<%= link_to "View CV", #applicant.cover.attachment.url, :target => "_blank" %>
Maybe there is way to preview links but for the moment that's fine.
You might consider using PDF-JS. There is a Rails gem but it hasn't been updated in 2 years. I would probably just download the latest version.
I'm using paperclip to upload images in rails, the images are saved well, but then, <%= #user.avatar.url %> returns this:
/system/users/avatars/000/000/001/original/1000203288934_DOCF635653TS102451125.gif%3F1416704056
/system/users/avatars/000/000/001/original/10407722_1175881652452049_8262371134443675175_n.jpg%3F1416705182
instead of just:
/system/users/avatars/000/000/001/original/1000203288934_DOCF635653TS102451125.gif
/system/users/avatars/000/000/001/original/10407722_1175881652452049_8262371134443675175_n.jpg
It happens for every image I upload. Where the hell that %3F-whatever at the end of the url comes from? What I'm doing wrong?
That is what Paperclip uses for cache-busting. If you want to remove it, just call #user.avatar.url(:original, timestamp: false)
You can also disable this globally by putting the following in the config/initializers/paperclip.rb file.
Paperclip::Attachment.default_options[:use_timestamp] = false
This answer explains why you may want cache-busting in place though.
I'm trying to follow this tutorial.
When I'm adding .pdf to my url it does nothing. My controller has:
respond_to :html, :pdf.
My mime type has been declared.
I tried this too:
respond_to do |format|
format.html
format.pdf {
html = render_to_string(:layout => false , :action => "www.google.fr")
kit = PDFKit.new(html)
send_data(kit.to_pdf, :filename => "candidats.pdf", :type => 'application/pdf')
return # to avoid double render call
}
end
but it does not work and I don't get errors. My browser keep waiting for localhost, but nothing happens.
So how should I try to use pdfkit ?
edit 2 :
According to my rails' logs, rails render successfully the HTML. I saw this in the .log, rails doesn't send it to webrick nor to my browser. And my browser keeps waiting, and waiting and nothing happen. I only have little pictures here.
edit 3 : My webrick server seem unable to respond to other request, once he starts getting a .pdf version of my url, any ideas ?
edit 4 :
I am using rails 3.1, wkhtmltopdf 0.9.5 (windows installer) and pdfkit 0.5.2
I found a better way to access my .pdf urls even in developpement mode.
# Enable threaded mode
config.threadsafe!
# Code is not reloaded between requests
#config.cache_classes = true
Config.cache_classes is a comment, cause i had some problems when it wasn't. This way pdfkit works wonder even with rails 3.1. But, you don't reload code between requests.
That's not really a problem, cause you first work on your html, and you switch configuration, in order to check the pdf result. This way you don't have to bother about your production database.
Thanks to another stack overflow answer I got part of solution.
This works:
html = '<html><body>Toto de combats</body></html>'
#pdf = PDFKit.new(html)
send_data #pdf.to_pdf, :filename => "whatever.pdf",
:type => "application/pdf",
:disposition => "attachement"
You can replace attachement by inline, so the pdf is displayed in your browser.
In the stack overflow answer I spoke about (I don't remember the link), the .to_pdf was missing, but is mandatory. Otherwise PDF reader doesn't recognize it.
I'm trying to get this work with a .pdf url.
Edit 3:
My problem with .pdf urls is solved. known issue with rails 3.1, but google was unable to find them.
explanation : explanation
Workaround (hadn't tryied yet). workaround
With paperclip, how can you get paperclip to use full urls like http://mysite.com/image/asdasd.png
versus /image/asdad.png
thanks
Once you configure the :url interpolation string to your satisfaction, you can link to attachments with the full URL using something like:
def attachment_path(attachment)
attachment.url
end
def attachment_url(attachment)
"#{root_url}#{attachment.url.gsub(/^\//, '')}"
end
Assuming you want the behavior to work like the _url helpers on the controller/view level, its a little complicated as paperclip functions without the benefit of knowing the host from the request. An easy way to get around this is to define the constant HOST in the config/environments/ENV.rb and then passing the url parameter to has_attachment like
:url => "http://#{HOST}/:path"
or whatever your url rules are.
You can also side step this issue by using S3, which is kind of a life saver
If you are uploading files to amazon S3 then s3.url gives the full image path. But in case of local file storage, you can set :url option also
I have paper_clip installed on my Rails 3 app, and can upload a file - wow that was fun and easy!
Challenge now is, allowing a user to upload multiple objects.
Whether it be clicking select fileS and being able to select more than one. Or clicking a more button and getting another file upload button.
I can't find any tutorials or gems to support this out of the box. Shocking I know...
Any suggestions or solutions. Seems like a common need?
Thanks
Okay, this is a complex one but it is doable. Here's how I got it to work.
On the client side I used http://github.com/valums/file-uploader, a javascript library which allows multiple file uploads with progress-bar and drag-and-drop support. It's well supported, highly configurable and the basic implementation is simple:
In the view:
<div id='file-uploader'><noscript><p>Please Enable JavaScript to use the file uploader</p></noscript></div>
In the js:
var uploader = new qq.FileUploader({
element: $('#file-uploader')[0],
action: 'files/upload',
onComplete: function(id, fileName, responseJSON){
// callback
}
});
When handed files, FileUploader posts them to the server as an XHR request where the POST body is the raw file data while the headers and filename are passed in the URL string (this is the only way to upload a file asyncronously via javascript).
This is where it gets complicated, since Paperclip has no idea what to do with these raw requests, you have to catch and convert them back to standard files (preferably before they hit your Rails app), so that Paperclip can work it's magic. This is done with some Rack Middleware which creates a new Tempfile (remember: Heroku is read only):
# Embarrassing note: This code was adapted from an example I found somewhere online
# if you recoginize any of it please let me know so I pass credit.
module Rack
class RawFileStubber
def initialize(app, path=/files\/upload/) # change for your route, careful.
#app, #path = app, path
end
def call(env)
if env["PATH_INFO"] =~ #path
convert_and_pass_on(env)
end
#app.call(env)
end
def convert_and_pass_on(env)
tempfile = env['rack.input'].to_tempfile
fake_file = {
:filename => env['HTTP_X_FILE_NAME'],
:type => content_type(env['HTTP_X_FILE_NAME']),
:tempfile => tempfile
}
env['rack.request.form_input'] = env['rack.input']
env['rack.request.form_hash'] ||= {}
env['rack.request.query_hash'] ||= {}
env['rack.request.form_hash']['file'] = fake_file
env['rack.request.query_hash']['file'] = fake_file
if query_params = env['HTTP_X_QUERY_PARAMS']
require 'json'
params = JSON.parse(query_params)
env['rack.request.form_hash'].merge!(params)
env['rack.request.query_hash'].merge!(params)
end
end
def content_type(filename)
case type = (filename.to_s.match(/\.(\w+)$/)[1] rescue "octet-stream").downcase
when %r"jp(e|g|eg)" then "image/jpeg"
when %r"tiff?" then "image/tiff"
when %r"png", "gif", "bmp" then "image/#{type}"
when "txt" then "text/plain"
when %r"html?" then "text/html"
when "js" then "application/js"
when "csv", "xml", "css" then "text/#{type}"
else 'application/octet-stream'
end
end
end
end
Later, in application.rb:
config.middleware.use 'Rack::RawFileStubber'
Then in the controller:
def upload
#foo = modelWithPaperclip.create({ :img => params[:file] })
end
This works reliably, though it can be a slow process when uploading a lot of files simultaneously.
DISCLAIMER
This was implemented for a project with a single, known & trusted back-end user. It almost certainly has some serious performance implications for a high traffic Heroku app and I have not fire tested it for security. That said, it definitely works.
The method Ryan Bigg recommends is here:
https://github.com/rails3book/ticketee/commit/cd8b466e2ee86733e9b26c6c9015d4b811d88169
https://github.com/rails3book/ticketee/commit/982ddf6241a78a9e6547e16af29086627d9e72d2
The file-uploader recommendation by Daniel Mendel is really great. It's a seriously awesome user experience, like Gmail drag-and-drop uploads. Someone wrote a blog post about how to wire it up with a rails app using the rack-raw-upload middleware, if you're interested in an up-to-date middleware component.
http://pogodan.com/blog/2011/03/28/rails-html5-drag-drop-multi-file-upload
https://github.com/newbamboo/rack-raw-upload
http://marc-bowes.com/2011/08/17/drag-n-drop-upload.html
There's also another plugin that's been updated more recently which may be useful
jQuery-File-Upload
Rails setup instructions
Rails setup instructions for multiples
And another one (Included for completeness. I haven't investigated this one.)
PlUpload
plupload-rails3
These questions are highly related
Drag-and-drop file upload in Google Chrome/Chromium and Safari?
jQuery Upload Progress and AJAX file upload
I cover this in Rails 3 in Action's Chapter 8. I don't cover uploading to S3 or resizing images however.
Recommending you buy it based solely on it fixing this one problem may sound a little biased, but I can just about guarantee you that it'll answer other questions you have down the line. It has a Behaviour Driven Development approach as one of the main themes, introducing you to Rails features during the development of an application. This shows you not only how you can build an application, but also make it maintainable.
As for the resizing of images after they've been uploaded, Paperclip's got pretty good documentation on that. I'd recommend having a read and then asking another question on SO if you don't understand any of the options / methods.
And as for S3 uploading, you can do this:
has_attached_file :photo, :styles => { ... }, :storage => :s3
You'd need to configure Paperclip::Storage::S3 with your S3 details to set it up, and again Paperclip's got some pretty awesome documentation for this.
Good luck!