Iam trying to add Content-Disposition to my docx files in s3. Something along the lines of: Content-Disposition: attachment; filename="filename.docx". I want to do this because IE (< 9) downloads docx files as zip files. After some googling I found that there is a workaround for this, by adding a content-disposition to the content as well. I tried using the before_post_process call back and did
before_post_process :set_content_disposition
def set_content_disposition
filename = self.attachment.instance.attachment_file_name
self.attachment.instance_write(:content_disposition, "attachment; filename="+filename)
end
But, it still downloads as zip file. Is there a way to correctly do this.
Prozac's answer (using before_post_process to edit the options) didn't work for me. However, there's now a simpler method, anyway. You can pass a proc directly to the :s3_headers key in the options hash of your has_attached_file call:
has_attached_file :attachment, {
...,
:s3_headers => lambda { |attachment|
# pass whatever you want in place of "attachment.name"
{ "Content-Disposition" => "attachment; filename=\"#{attachment.name}\"" }
},
...
}
I finally found a way .. there is a before_post_process callback with paperclip gem.
we can do something like this..
has_attached_file :sample
before_post_process :set_content_dispositon
def set_content_dispositon
self.sample.options.merge({:s3_headers => {"Content-Disposition" => "attachment; filename="+self.sample_file_name}})
end
I can't help you with paperclip but the correct MIME Type/Content Type for docx files is application/vnd.openxmlformats-officedocument.wordprocessingml.document.
Using that will stop IE downloading them as zip files.
Here are all the MIME types for the new office formats.
Extension MIME Type
.xlsx application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.xltx application/vnd.openxmlformats-officedocument.spreadsheetml.template
.potx application/vnd.openxmlformats-officedocument.presentationml.template
.ppsx application/vnd.openxmlformats-officedocument.presentationml.slideshow
.pptx application/vnd.openxmlformats-officedocument.presentationml.presentation
.sldx application/vnd.openxmlformats-officedocument.presentationml.slide
.docx application/vnd.openxmlformats-officedocument.wordprocessingml.document
.dotx application/vnd.openxmlformats-officedocument.wordprocessingml.template
.xlam application/vnd.ms-excel.addin.macroEnabled.12
.xlsb application/vnd.ms-excel.sheet.binary.macroEnabled.12
Prozac,
I think that in Paperclip you have to set s3_header['Content-Disposition'] hash but I'm in the same issue given that s3_header hash is not interpolated I still can't figure out how to put the filename there without patch Paperclip
check this solution http://groups.google.com/group/paperclip-plugin/browse_thread/thread/bff66a0672a3159b
Related
I'm currently using Rails 5.2.2.
I'm trying to copy one image between 2 models. So I want 2 files, and 2 entries in blobs and attachments.
My original object/image is on AWS S3.
My original model is photo, my target model is image.
I tried this:
image.file.attach(io: open(best_photo.full_url), filename: best_photo.filename, content_type: best_photo.content_type)
full_url is a method added in photo.rb:
include Rails.application.routes.url_helpers
def full_url
rails_blob_path(self.file, disposition: "attachment", only_path: true)
end
I got this error, as if the file was not found:
No such file or directory # rb_sysopen -
/rails/active_storage/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBHZz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--2f865041b01d2f2c323a20879a855f25f231289d/881dc909-88ab-43b6-8148-5adbf888b399.jpg?disposition=attachment
I tried other different things such (this method is used when displaying images with image_tag() and works correctly:
def download_variant(version)
variant = file_variant(version)
return rails_representation_url(variant, only_path: true, disposition: "attachment")
end
Same error.
I verified and the file is present on the S3 server.
What did I miss ?
Thanks.
You can attach the source blob to the target:
image.file.attach best_photo.file.blob
Updated for Rails 6+ - this worked for me
image.file.attach(io: StringIO.new(best_photo.download),
filename: best_photo.filename,
content_type: best_photo.content_type)
OK, I got it.
I used service_url:
image.file.attach(io: open(best_photo.file_variant("large").service_url), filename: best_photo.file.blob.filename, content_type: best_photo.file.blob.content_type)
It's possible to use file_blob instead of file.blob
You can copy using update
image.update(file: best_photo.file_blob)
or attach
image.file.attach(best_photo.file_blob)
Both methods actually just create new blob association, there is no physical copying of attachment. So be careful when you call image.blob.purge or if you have dependent: :purge_later
If you want real copy you need to read attachment with ActiveStorage::Blob#download
image.file.attach(
io: StringIO.new(best_photo.file.download),
filename: best_photo.file.filename,
content_type: best_photo.file.content_type
)
or with ActiveStorage::Blob#open
best_photo.file_blob.open do |tempfile|
image.file.attach(
io: tempfile,
filename: best_photo.file.filename,
content_type: best_photo.file.content_type
)
end
Be careful with large files
I need to upload attachments with extension of .txt but evaluate to mime-type "application/octet-stream" by the file command. The file is automatically generated by a piece of equipment and it is not feasible to rename it before uploading. I have tried:
class Book < ActiveRecord::Base
has_attached_file :excerpt
validates_attachment_content_type :excerpt, content_type: { content_typ: ["text/plain", "application/octet-stream"]}
validates_attachment_file_name :excerpt, matches: [/txt\z/]
end
but I always get an error that the detected content-type does not match the inferred content-type:
Command :: file -b --mime '/tmp/313a40bb0448477e051da1e2cba2c20120161027-19345-lrhf6t.txt'
[paperclip] Content Type Spoof: Filename Sample.txt (text/plain from Headers, ["text/plain"] from Extension), content type discovered from file command: application/octet-stream. See documentation to allow this combination.
The error message says to look in documentation for a way to allow the combination but I have not been able to find anything that looks like a workaround. Saw this discussion but it was for v4.
Thanks for the pointer, Chris. Guess I didn't read that section of the README file carefully enough. (BTW, fixing the typo didn't make any difference.)
So, the solution is as follows:
In config/initializers/paperclip.rb:
Paperclip.options[:content_type_mappings] = {
txt: %w(application/octet-stream)
}
In the model:
class Book < ActiveRecord::Base
has_attached_file :excerpt
validates_attachment_file_name :excerpt, matches: [/txt\z/]
end
This works whether the actual .txt file is a 'text/plain' or 'application/octet-stream'.
Is it because of the misspelled content_type key? (You have it entered as content_typ.)
If the first suggestion doesn't work, I think that in your case, you'd want to do this in config/initializers/paperclip.rb (according to instructions in the README's Security Validations section):
Paperclip.options[:content_type_mappings] = {
txt: %w(text/plain application/octet-stream)
}
I am attempting to copy pdf files from dropbox to paperclip. Everything seems to work except that the pdf's fail to load when I try and view them from my rails application.
I have paperclip working:
class Document < ActiveRecord::Base
has_attached_file :file, content_type: ["application/pdf", "application/x-pdf"]
validates_attachment_content_type :file, content_type: ["application/pdf", "application/x-pdf", "application/rtf", 'application/x-rtf', 'text/rtf', 'text/plain']
end
To upload the file to paperclip I do the following:
contents = DropboxClient.new(DROPBOX_AUTH_TOKEN).get_file(PATH_TO_MY_PDF)
file = StringIO.new(contents)
file.class.class_eval{ attr_accessor :content_type, :original_filename }
file.content_type = "application/pdf"
file.original_filename = "my_pdf.pdf"
Document.create(file: file)
But when I click on a link that sends to a send_data(#document.file, filename: #document.file_file_name) the file is downloaded but cannot be opened. The downloaded file has content type of pdf and says it's 4kb where as the original is 10kb.
If it's helpful the contents that DropboxClient.new(DROPBOX_AUTH_TOKEN).get_file(PATH_TO_MY_PDF) returns is of the form
\x03Y\x8E\xCB\xC3\x97Zi\xA5\x92\xBB\xF1\xFD\xCD\x1D\xF5\x18\xF4\x95\xEB/\xD3\xAB\xCF\x9D\xB6\x02\x89\xDB\x9E\xE9\xBFJ!pF\xCB\xEA(\xC4B*\
but much longer.
Turns out everything was working fine. But in using send data you need to send the raw data, not the paperclip file object (duh!). Changing to
send_data(Paperclip.io_adapters.for(#document.file).read, filename: #document.file_file_name)
solved my problems.
I have spent a lot of time trying to attach a file into a mongoid paperclip field. The examples that I have found, always do the same:
my_model_instance = MyModel.new
file = File.open(file_path)
my_model_instance.attachment = file
file.close
my_model_instance.save!
as you can see in How to set a file upload programmatically using Paperclip.
The model that I have done is:
class Logotype
include Mongoid::Document
include Mongoid::Paperclip
has_mongoid_attached_file :logo,
styles: {large: ['640x160'], small: ['300x300>']},
size: { in: 0..3.megabytes },
content_type: [ "image/jpg", "image/png", "image/bmp" ],
storage: :filesystem,
path: ':rails_root/public/resource/resources/:id/:style.:extension',
url: '/logos/resources/:id/:style.:extension'
validates_presence_of :logo
validates_uniqueness_of :logo
end
However I have always the same big error:
NoMethodError: undefined method `__bson_dump__' for /logos/resources/51b5bfaa69fd8a7941000005/original.jpg?1370865578:Paperclip::Attachment
...
Could someone help me? Thanks in advance!
PD: Sorry for my English level.
This is an old question but I just thought I'd share my solution in case someone else finds themselves here.
For me, this was happening in the Moped::BSON::Extensions::Hash module while trying to log the request for a save action. Your stack may be different, but basically the problem occurs when trying to dump data that Mongoid doesn't know how to handle. In my case it was a file upload, ActionDispatch::Http::UploadedFile, but for the OP it's a Paperclip::Attachment.
I solved it by just removing those key/value pairs from the request parameters, e.g.
# recursively remove UploadedFile from a Hash of request parameters
def remove_files(params)
p = proc do |_, v|
v.delete_if(&p) if v.respond_to? :delete_if
v.is_a?(ActionDispatch::Http::UploadedFile)
end
params.delete_if(&p)
end
There might be a better solution that logs the filename or something instead, but I found it easier just to get rid of it.
My rails 3 app on heroku receives incoming emails. I want to be able to accept attachments but can't get rails to process the attachments without erroring.
The ideal would be to pass the attachment provided by ActionMailer.
message_all = Mail.new(params[:message])
message_all.attachments.each do |a|
attachments.each do |a|
.attachments.build(
:attachment => a
)
end
end
It errors with: NoMethodError (undefined methodrewind' for #)`
Where attachments is a model, with attachment is paperclip
Ideas y? Is there a different way to pass the attachment = a , to paperclip?
I tried another approach, creating a tempfile:
tempfile = File.new("#{Rails.root.to_s}/tmp/#{a.filename}", "w+")
tempfile << a.body
tempfile.puts
attachments.build(
:attachment => File.open(tempfile.path) )
The problem with the tempfile is files without extentions "blah" instead of "blah.png" are breaking paperclip which is why I want to avoid the tempfile. and creating Identity errors, imagemagick doesn't know what they are w/o the ext.
hugely appreciate any advice on this.
The problem with the methods that you are using is that they don't contain all of the necessary information for paperclip like the content type and the original filename. I wrote a blog post about this a while back and how you could fake the format and use an email attachment as a paperclip attachment.
The bottom line was to do this:
file = StringIO.new(attachment)
file.class.class_eval { attr_accessor :original_filename, :content_type }
file.original_filename = attachment.filename
file.content_type = attachment.mime_type