When I click a link, the amazon file is downloading fine. I have thousands of pdf files in amazon. Now mongoid id as the name of that amazon files. When I download the the files its save with that id's. But I would like to rename the file before save that file to local. I have name field in my mongoid.
include Mongoid::Paperclip
has_mongoid_attached_file :profile_doc
when I link a like this controller action will call
def download
if #company.send(doc).exists?
redirect_to #company.send(doc).expiring_url
else
respond_with_error(:not_found)
end
end
How I rename the file when download the file. now file is downloading like this 50sfdkkmzd.pdf I would like to save name.pdf.
Thanks for your time.
try this, it should work fine
def download
if #company.send(doc).exists?
data = open(#company.send(doc).expiring_url)
send_data data.read, :filename => "name.pdf", :type => data.content_type
else
respond_with_error(:not_found)
end
end
Related
Fairly new to using ActiveStorage (love it so far!), but I am running into an issue with trying to figure out how to update a previously attached item.
I have a front-end form that allows a user to upload a PDF, my backend then takes the PDF and scrapes it for data, then exports the data to an excel spreadsheet. My code (when I call to re-attach the export), I see my item in my specified s3 bucket, but its a hashed key name.
class Export < ApplicationRecord
has_one_attached :item
def process_pdf!
pdf_file_name = "#{item.blob.key}_#{item.blob.filename.to_s}"
xls_file_name = "#{item.blob.key}_#{item.blob.filename.to_s.sub('pdf', '')}"
file = "#{Rails.root}/tmp/#{pdf_file_name}"
File.open(file, 'wb') do |f|
f.write(pdf.download)
end
PdfScraper.call(pdf_file: file, output_name: xls_file_name)
self.item.attach(
io: File.open("#{Rails.root}/tmp/#{xls_file_name}"),
filename: "#{xls_file_name}.xlsx",
content_type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
)
File.delete(file)
true
end
end
How do I attach the generated excel spreadsheet?
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 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 am looking for a way to create multiple csv files and download them as one zip archive within one request in my rails application.
To build the archive I use rubyzip gem - to download it just the rails built-in function send_data. The problem I have is that rubyzip's add-function requires a pathname to load files from. But there is no path as my csv files are created within the same request.
Some Code:
# controller action to download zip
def download_zip
zip = #company.download_all
send_data zip, filename: "abc.zip", type: 'application/zip'
end
# method to create zip
def download_all
Zip::File.open('def.zip', Zip::File::CREATE) do |zipfile|
self.users.each do |user|
#some magic to combine zipfile.add() and user.to_csv
end
end
end
# method to create csv
def to_csv
CSV.generate do |csv|
#build awesome csv
end
end
Is there a way to save my csv files temporarely at some directory, that I can pass a pathname to zipfile.add()?
Nice weekend everybody and happy coding!
You could either write your CSV output into a temporary file and call zipfile.add() on that, but there is a cleaner solution:
zipfile.get_output_stream("#{user.name}.csv") { |f| f.puts(user.to_csv) }
See http://rdoc.info/github/rubyzip/rubyzip/master/Zip/File#get_output_stream-instance_method for more details on get_output_stream - you can also pass additional parameters to specify attributes for the file to be created.
get_output_stream doesn't work for me. However, the updated method Zip::OutputStream.write_buffer helps
https://gist.github.com/aquajach/7fde54aa9bc1ac03740feb154e53eb7d
The example adds password protection to the file as well.
I'm using jpegcam to allow a user to take a webcam photo to set as their profile photo. This library ends up posting the raw data to the sever which I get in my rails controller like so:
def ajax_photo_upload
# Rails.logger.info request.raw_post
#user = User.find(current_user.id)
#user.picture = File.new(request.raw_post)
This does not work and paperclip/rails fails when you try to save request.raw_post.
Errno::ENOENT (No such file or directory - ????JFIF???
I've seen solutions that make a temporary file but I'd be curious to know if there is a way to get Paperclip to automatically save the request.raw_post w/o having to make a tempfile. Any elegant ideas or solutions out there?
UGLY SOLUTION (Requires a temp file)
class ApiV1::UsersController < ApiV1::APIController
def create
File.open(upload_path, 'w:ASCII-8BIT') do |f|
f.write request.raw_post
end
current_user.photo = File.open(upload_path)
end
private
def upload_path # is used in upload and create
file_name = 'temp.jpg'
File.join(::Rails.root.to_s, 'public', 'temp', file_name)
end
end
This is ugly as it requires a temporary file to be saved on the server. Tips on how to make this happen w/o the temporary file needing to be saved? Can StringIO be used?
The problem with my previous solution was that the temp file was already closed and therefore could not be used by Paperclip anymore. The solution below works for me. It's IMO the cleanest way and (as per documentation) ensures your tempfiles are deleted after use.
Add the following method to your User model:
def set_picture(data)
temp_file = Tempfile.new(['temp', '.jpg'], :encoding => 'ascii-8bit')
begin
temp_file.write(data)
self.picture = temp_file # assumes has_attached_file :picture
ensure
temp_file.close
temp_file.unlink
end
end
Controller:
current_user.set_picture(request.raw_post)
current_user.save
Don't forget to add require 'tempfile' at the top of your User model file.