How do you create a new file in a CarrierWave process? - ruby-on-rails

My user uploads a zip file with 3 files (A.ttf, A.svg, A.otf) and I want to store the original zip plus the 3 font files inside it. I've created the 3 versions with this code
version :ttf
process :font => :ttf
end
version :svg
process :font => :svg
end
version :otf
process :font => :otf
end
It successfully saves 4 copies of the original file, all with the proper file name. However, I don't know how to get CarrierWave to store the individual files. This code doesn't work. :(
def font(format)
new_file = nil
# Loop through the zip file and extract the files
Zip::ZipFile.open(#file.file) do |files|
files.each do |f|
next unless f.file?
filename = f.name.split("/").last
ext = filename.split('.').last
# Save the file with the proper file extension
new_file = f if ext == format
end
# Return the file to be stored by CarrierWave
new_file
end

OK, after many hours of banging my head against the wall the light finally came on. The solution is in how CarrierWave processes the upload. When you define a version, CW duplicates the file with a new name ([version name]_original_filename) and gives it to you in the current_path variable. You can do anything you want with this file reference (ie open the file and truncate it, or fill it with random date, etc.) and when you get done CW will store the file for you.
Somehow I missed the connection and when I realized what was going on it almost blinded me. I'm answering this question here so that it might help some other poor soul lost in the dark. And to show the world my ignorance. :/

I dont know about CarrierWave. But you are returnng zip file object back. Is it what you want to pass or do you want the name of the file to be passed? Or else do you want the file to be extracted and pass the extracted file path back?

Related

How to implement a user creating a file via form and then downloading it in rails?

I am building an online translation platform. When a job is done being translated and saved, I want the user to be able to download the translated version as a text file. It is currently saved in a string in the model called "target_text".
I know in ruby I can use this method:
File.open("translation.txt", 'w') {|f| f.write("my translated string") }
I am assuming I could tack the location for the file to be saved in front of the "translation.txt", but I am not sure what folder within my app I should specify?
Furthermore I want this file to be attached to the "job" object in the same way that paperclip can attach files, the difference being it's initiated server side. How should I go about this?
I have googled all over looking for an answer to this, and I want to make sure I do it in the cleanest way possible. I would really appreciate even directions to a good place to look to understand this concept.
I don't quite understand the question, but I hope this could help...
Instead of using
File.open("translation.txt", 'w') {|f| f.write("my translated string") }
try using the following
Tempfile.open(['translation', '.txt'], Rails.root.join('tmp')) do |file|
# this will create a temp file in RAILS_ROOT/tmp/ folder
# you can replace the 'translation' text part to any auto generated text for example
# Tempfile.open([#user.id.to_s, '_translation.txt'] will create
# RAILS_ROOT/tmp/1_translation.1fe2ed.txt
# the 1fe2ed is generated by Tempfile to avoid conflicting
begin
file << "my translated string"
# this creates the file
# add all the processing you need here... cause the next ensure block
# will close and delete this temp file... so that the tmp dir doesn't get big.
# you can for example add the file to paperclip attachment
#user.translation = file
# assuming that user has paperclip attachment called translation
ensure
# close and delete file
file.close
file.unlink
end
end
also check the Tempfile docs... this is the practice i've been using... not sure if it's the best or not.. but it didn't create any issues so far
(even with paperclip s3 storage)

When using paperclip on Rails3, the some characters( # and ~) get erased or altered from the file name when uploading

I'm not sure if this is a paperclip issue. Tried it on gitlab and the same thing happened.
I have a back end for an iOS app written in Rails, and when I upload an image file with the # character in the filename, it gets erased upon uploading, if I have a file named,
aaa#2x.jpg
it gets saved as
aaa2x.jpg
Also, ~ gets converted into a _.
This is a problem because iOS apps presume that retina supported images are named with the #2x prefix.
I can regex the file name post upload and change it in the database and rename the file, but that seems like an odd hack to do, anyone have any idea whats happening? How to have the file name saved properly to begin with?
According to this article: http://en.wikipedia.org/wiki/HFS_Plus, you should be able to use any character, including NUL in file names. But OS APIs may limit some characters for legacy reasons.
It can be server or client issue, try to debug your application and check file name provided in request.request_parameters it should contain valid file name.
If you going to use uploaded files in URLs you should transliterate them before upload, this also resolve your problem. To do this you can use this extension:
module TransliteratePaperclip
def transliterate_file_name(paperclip_file)
paperclip_file=[paperclip_file] unless paperclip_file.is_a?(Enumerable)
paperclip_file.each do |file|
filename=read_attribute("#{file}_file_name")
if filename.present?
extension = File.extname(filename).gsub(/^\.+/, '')
filename = filename.gsub(/\.#{extension}$/, '')
self.send(file).instance_write(:file_name, "#{filename.parameterize}.#{extension.parameterize}")
end
end
end
end
# include the extension
ActiveRecord::Base.send(:include, TransliteratePaperclip)
put this code in /config/initializers/paperclip_transliterate.rb and in your paperclip model:
before_post_process { |c| transliterate_file_name(:file) }
where :file is attribute defined by has_attached_file.

Parsing rails uploaded temporary file more then once

I'm new to rails and I'm currently trying to parse an uploaded file to rails. However, after I "read" the file once I cannot read it again. From what I've read online it appears that rails immediately deletes the uploaded file. Is there a way to make the file persistent? My code is as follows
file_param = params[:sequence]
file_param.read.each do |l|
# do stuff
end
file_param.read.each do |l|
# do stuff again. this is not being called.
end
I've thought of using paperclip or some other storage gem, but I don't need to store the files, simply read their contents. Thanks!
Read it into an array, if you really need to go over it multiple times, or just save it.

How do you access the raw content of a file uploaded with Paperclip / Ruby on Rails?

I'm using Paperclip / S3 for file uploading. I upload text-like files (not .txt, but they are essentially a .txt). In a show controller, I want to be able to get the contents of the uploaded file, but don't see contents as one of its attributes. What can I do here?
attachment_file_name: "test.md", attachment_content_type: "application/octet-stream", attachment_file_size: 58, attachment_updated_at: "2011-06-22 01:01:40"
PS - Seems like all the Paperclip tutorials are about images, not text files.
In Paperclip 3.0.1 you could just use the io_adapter which doesn't require writing an extra file to (and removing from) the local file system.
Paperclip.io_adapters.for(attachment.file).read
#jon-m answer needs to be updated to reflect the latest changes to paperclip, in order for this to work needs to change to something like:
class Document
has_attached_file :revision
def revision_contents(path = 'tmp/tmp.any')
revision.copy_to_local_file :original, path
File.open(path).read
end
end
A bit convoluted as #jwadsack mentioned using Paperclip.io_adapters.for method accomplishes the same and seems like a better, cleaner way to do this IMHO.
To access the file you can use the path method:
csv_file.path
http://rdoc.info/gems/paperclip/Paperclip/Attachment#path-instance_method
This can be used along with for example the CSV reader.
Here's how I access the raw contents of my attachment:
class Document
has_attached_file :revision
def revision_contents
revision.copy_to_local_file.read
end
end
Please note, I've omitted my paperclip configuration options and any sort of error handling.
You would need to load the contents of the file (using Rubys File.open) into a variable before you show it. This may be an expensive operation if your app gets lots of use, so it may be worthwhile reading the contents of the file and putting it into a text column in your database after uploading it.
Attachment already inherits from IOStream. http://rdoc.info/github/thoughtbot/paperclip/master/Paperclip/Attachment
So it should just be "#{attachment}" or <% RDiscount.new(attachment).to_html %> or send_data(attachment). However you wanted to display the data.
This is a method I used for upload from paperclip to active storage and should provide some guidance on temporarily working with a file in memory. Note: This should only be used for relatively small files.
Written for gem paperclip 6.1.0
Where I have a simple model
class Post
has_attached_file :image
end
Working with a temp file in ruby so we do not have to worry about closing the file
Tempfile.create do |tmp_file|
post.image.copy_to_local_file(nil, tmp_file.path)
post.image_temp.attach(
io: tmp_file,
filename: post.image_file_name,
content_type: post.image_content_type
)
end

How to delete the temporary files automatically in ruby-rails?

My Rails app has to process and generate PDF XFA files and send to the user/browser.
Its working fine. But the issue is that before sending the file to the user, it creates 2 files in the rails tmp directory.
If 10 requests come to the pdf_controller, the number of the temp files in the tmp directory will double and it will eat up the space.
After searching around I thought that Sweeper will come to the rescue. But not much knowledge about Sweeper.
So, can anyone plz suggest which way to go?
Tempfile will delete files when the object is finalized.
Tempfile on Rdoc
Example:
def get_pdf
model = Model.find(params[:id])
file = Tempfile.new
model.to_pdf(file)
send_file file.path, ...
end
I can provide a better example if you paste your code into your question.
You could use a cron task, that deletes the files every n minutes, or, you could order the deletion from the controller itself.

Resources