I have a custom file type (.map) that I am unzipping from a Gzip file and then writing to a new file in order to pass it along to Paperclip and upload to s3. My problem is that the type should be an xml, while it is saving as a text document instead with all xml formatting correct. I need a way to convert it into the xml type and then save that as a new File object before passing it along.
Here is my code so far:
Zlib::GzipReader.open(f.tempfile) do |gz|
puts gz.orig_name
#tmp = File.new(gz.orig_name, "w+")
while chunk = gz.read(16*1024) do
#tmp.write(chunk)
end
end
reader = #tmp.read
s = location.posts.create!(
subject: #email.subject,
from: #email.from[:email],
mapfile: #tmp)
}
ideally i will be passing mapfile the xml type file, but right now it seems to be text
Update:
So now I have set my post.rb to do this, and added a name attribute to post containing the original file name:
has_attached_file :mapfile,
:preserve_files => "true",
:path =>
':rails_root/non-public/system/:id/:basename.:extension',
:url => '/:class/:id/mapfiles',
:s3_headers => lambda { |attachment| {'Content-Disposition' => "attachment; filename = #{attachment.name}"}}
And this works perfectly!
It sounds like you are talking about `Content-Type'. When you save a file to the filesystem, you can't set this: the system will decide what to use based on the file extension and possibly by analysing the contents, if it's a text file.
However, you can set the content type when you serve a file to someone's browser, and when you upload it to S3. See here for the latter Setting the Content-Type in direct to S3 upload using Rails and jQuery File Upload
Related
I am using spreadsheet gem to generate .xls file. After writing it to a file, I am trying to send to client browser for download.
Below is the code in rails
workbook = Spreadsheet::Workbook.new
# Constructed the data
file = "/path/to/file/sheet.xls"
workbook.write file
send_file file
This file when opened contains expected data in ideal format.
Below is the code in js:
CustomRestService.custom_post("report",{report_data: angular.toJson($scope.report_data)},"download_xls",{}).then (data)->
if data
hiddenElement = document.createElement('a')
angular.element(document.body).append(hiddenElement)
hiddenElement.href = 'data:attachment/xls,' + encodeURI(data)
hiddenElement.target = '_blank'
hiddenElement.download = "report.xls"
hiddenElement.click()
hiddenElement.remove()
But the file getting downloaded in browser contains junk data. I tried multiple solutions like below:
Using send_data, instead of send_file
Generated xls data and wrote to StringIO object to directly download
Constructed Blob object in js, with type as "application/vnd.ms-excel" and trying to download it.
All attempts failed, as I am missing something. All suggestions are welcome.
filename = "/path/to/file/sheet.xls"
tempfile = Tempfile.new(filename)
workbook = Spreadsheet::Workbook.new
...
workbook.write(tempfile.path)
send_file tempfile.path, :filename => filename
I create an xml file with:
xml_device_path = "#{xml_device_description.get_file_path_without_name}#{title}.xml"
File.open("#{xml_device_path}", 'w') do |f|
f.puts(content.to_xml)
end
to attach this file via paperclip to my model.
file = File.open("#{xml_device_path}")
xml_device_description.xml = file
file.close
The resulting file has the content type "application/xml" but I need the content type "text/xml".
Is it possible to set or to manipulate the content type of an file or during the file creation?
Thanks a lot.
I have solved the problem as follows:
#change paperclip file content type
xml_device_description.xml.xml_content_type = "text/xml"
#save activeRecord
xml_description.save!
I just set a new content type to the paperclip column in the db...
I'm trying to upload a file through a form to AWS S3. Here is my controller right now:
s3 = Aws::S3::Client.new(access_key_id: AWS_CREDS[aws_env]['access_key_id'], secret_access_key: AWS_CREDS[aws_env]['secret_access_key'], region: "us-east-1")
resource = Aws::S3::Resource.new(client: s3)
obj = resource.bucket('mybucket').object(file_name)
obj.upload_file(file: params[:upload_file], acl: :private)
This returns a no implicit conversion of Hash into String error. This looks correct based on what I'm seeing in other examples so I'm not sure where I went wrong.
How do I access the file that was uploaded? p params[:upload_file] just returns the filename, I do not see a hash. Do I need to do further processing on the file before I am able to upload it?
Form:
= form_tag(form_path, :method => "POST", enctype: 'multipart/form-data') do
%input{:name => "authenticity_token", :type => "hidden", :value => form_authenticity_token}
.form-group
.col-sm-3
%label Document name or date
= text_field_tag('name', nil, class: 'form-control')
- if #errors and #errors['name']
%span{:class => "form-error"}
= #errors['name']
.col-sm-3
%label Document type
= select_tag('type', options_for_select(['1', '1'], ['2', '2']), class: 'form-control')
.col-sm-3
%label Select file
= file_field_tag 'upload_file'
- if #errors and #errors['upload_file']
%span{:class => "form-error"}
= #errors['upload_file']
.col-sm-3
%br
%input.btn.btn-primary.btn-sm{:type => "submit"}
First, you didn't tell us what params[:upload_file] is but if you're attempting to upload a file through a form and pass it along to the AWS upload via the params object it won't work. You have to give upload_file a path to the file you want to upload, that means it has to be on same filesystem as your Rails server. If you're currently in a development environment this may unintentionally work for you since it's on your local machine, but it will fail on a production server.
Second, you said want to access the file that was uploaded but p params[:upload_file] is printing filename? params[:upload_file] is the input, it won't contain any information about the uploaded file. If you want to access a successfully uploaded file you need to look at the url on the obj. Try calling obj.public_url. Of course, you will need to set acl: :private to acl:'public-read'.
Take a look at this example, it might help you.
EDIT:
params[:upload_file] is a not the uploaded file. It is StringIO? object, you have to finish the uploading job in the controller. This SO answer will help you properly do file uploads. Once you have successfully uploaded a file via Rails, you can take the path of that new file and pass it to the AWS upload.
I strongly advise not trying to get the Rails form file upload AND the AWS upload working in one giant sweep. Get one working, then the other. You can test AWS upload by reading my original answer and instead of trying to pass your params[:upload_file], just pass a string path to a known file on your local machine. For example, put a test text file in your /tmp directory, then pass that path /tmp/test_file to your upload_file call.
There is no need to save the file before you upload that to S3 Bucket.
Once you're in controller, your file is already stored in a temp directory.
So, to upload the file to S3 on AWS-SDK v 2.x you can do:
obj = S3_BUCKET.object('file_name')
obj.upload_file(File.expand_path(params[:file].tempfile))
Posting your file named 'file', controller will store that automatically in a temp folder.
params[:file].tempfile
Is a reference to a temporary file, and we need to get the PATH to the file by:
File.expand_path(params[:file].tempfile)
That is it ;)
I am using paperclip to upload resume in my applyforjobs.Its working fine,i mean i can get browse button to upload files.But when i show the view page its not showing the pdf file that i upload,instead its showing just the name of the file. I also checked that folder which gets generated by default and that folder contains the pdfs which i uploaded during create aaction,which means upload thing is working fine.but i am not able to show that pdf.
Following is the code in my applyforjob.rb model for paperclip attachment :
has_attached_file :resume,:styles => { :small => "150x150>" }
Following is the code of applyforjobs/form.html.haml for uploading file :
= f.label :resume, "Upload resume".html_safe
= f.file_field :resume
Following is the code of applyforjobs/show.html.haml for showing file :
= image_tag #appliedusers.resume.url(:small)
but its not showing that pdf file.What am i supposed to write to upload and show files like pdf or docs?
Since paperclip is a general purpose attachment uploading gem, as stated in it's Readme, it natively supports uploading files of any kind.
I suggest that you:
remove :styles => { :small => "150x150>" } parameter from the has_attached_file
write a paperclip callback which will generate a thumbnail image from pdf file
define a method in model, say resume_thumbnail, which will be returning a path to generated file
call the following in your view
= image_tag #appliedusers.resume_thumbnail
No wonder image_tag #appliedusers.resume.url(:small) doesn't work for you: paperclip knows nothing about PDFs. paperclip blindly sees PDF file as a common file, and thus unable to do any kind of processing applicable to images only.
# , After saving the pdf you need to create a image which convert pdf to image to show on browser
I did this like -
**self.save ##save pdf in paperclip
create_preview_image ##call this method
def create_preview_image
file_name = File.join(Rails.root, 'public', self.document.url.split('?')[0]) if self.document
return unless file_name.present?
pdf = Magick::ImageList.new(file_name)
return unless pdf.present?
png_file = Tempfile.new(["#{rand(9999).to_s}",'.png'])
pdf[0].write(png_file.path) do
self.quality = 100
end
self.preview = png_file
self.save
end**
I am trying to send an email containing a file attachment created by the user.
attachments[document.display_name] = File.read(document.public_filename)
This works in most conditions (including .docx, but fails for .xlsx files with the error:
invalid byte sequence in UTF-8
I am using attachment_fu to upload the attachments, and delayed_job to defer sending the emails, however the file I am trying to attach looks ok, and I can open it successfully outside the application.
I also saw a suggestion to change the code as follows, but it does not seem to help:
include an extra.
attachments[document.display_name] = { :content => File.read(document.public_filename), :transfer_encoding => :binary }
How can I make the code work for all attachment types?
You need to specify the mode or encoding to let it read the file as binary:
attachments[document.display_name] = File.read(document.public_filename, :mode => 'rb')
or
attachments[document.display_name] = File.read(document.public_filename, :encoding => 'BINARY')