I want to change the file name after downloading the zip file - ruby-on-rails

What I want to solve
I want to change the name of the file after downloading the zip. I was trying to figure out how to remove the directory name in the middle of this.
In this case, the intermediate directory name is "output".
I would like to know if there is a better way.
2_J000001719_1202テスト/output/WNS_UP用データ.txt
2_J000001719_1202テスト/output/Images/1051687701.jpg
↓
2_J000001719_1202テスト/WNS_UP用データ.txt
2_J000001719_1202テスト/Images/1051687701.jpg
Original Source Code
add_dir_name = "#{order.priority}_#{order.orderno}_#{company_name[0, 15]}"
Zip::File.open_buffer(obj) do |zip|
zip.each do |entry|
ext = File.extname(entry.name)
file_name = File.basename(entry.name)
dir_name = File.dirname(entry.name)
next if ext.blank? || file_name.count(".") > 1
dir = File.join(add_dir_name, dir_name)
FileUtils.mkpath(dir.to_s)
zip.extract(entry, dir + ext) {true}
file_name.force_encoding("UTF-8")
new_file_name = "#{dir}/#{file_name}"
new_file_name.force_encoding("UTF-8")
File.rename(dir + ext, new_file_name)
#input_dir << new_file_name
end
end
What I tried
I added this method to the source code, but it did not work.
new_dir = Dir.glob(dir_name+"/*").last
demdem = new_dir.split('/').last
new_file_name = dir.sub("/" + demdem, "")

Here's a generic function to move all files (recursively) from one dir to another:
orig_dir = "2_J000001719_1202テスト/output"
new_dir = "2_J000001719_1202テスト"
def move_all_files(orig_dir, new_dir)
Dir.glob("#{orig_dir}/**/*").each do |path|
File.move(path, path.gsub(orig_dir, new_dir))
end
end

Related

Access ActiveStorageBlob or ActiveStorageAttachment like it would be a native model

Would it be possible to access the ActiveStorageBlob or ActiveStorageAttachment like it would be a native model ?
E.g.
I want to do ActiveStorageBlob.first to access the first record of this model/table.
or. ActiveStorageAttachment.all.as_json to generate json formated print.
The background idea is to find a way how to dump the content of these ActiveStorage related tables as json formated files. Then change simething on these files, and load it back.
----Extending this text after got correct answer-----
Thank you very much Sarah Marie.
And I hope you know how to load the JSON data back into these tables ?
I have tried this :
dump_file_path = File.join(Rails.root, "backup", active_storage_blobs_file)
load_json = JSON.parse(File.read(dump_file_path))
load_json.each do |j|
ActiveStorage::Blob.create(j)
end
But thats not working.
ActiveModel::UnknownAttributeError (unknown attribute
'attachable_sgid' for ActiveStorage::Blob.)
ActiveStorage::Blob.first
ActiveStorage::Attachment.all.as_json
---- For second extended question ----
ActiveStorage::Blob.create_before_direct_upload!(
filename: j[:filename],
content_type: j[:content_type],
byte_size: j[:byte_size],
checksum: j[:checksum]
)
# or
ActiveStorage::Blob.create_before_direct_upload!(**j.symbolize_keys)
Reference: https://github.com/rails/rails/blob/5f3ff60084ab5d5921ca3499814e4697f8350ee7/activestorage/app/controllers/active_storage/direct_uploads_controller.rb#L8-L9
https://github.com/rails/rails/blob/098fd7f9b3d5c6f540911bc0c17207d6b48d5bb3/activestorage/app/models/active_storage/blob.rb#L113-L120
Now I have a complete solution, how to dump and load the ActiveStorage tables as JSON files.
...dump it
active_storage_blobs_file = "active_storage_blob.json"
active_storage_attachments_file = "active_storage_attachment.json"
puts("...dump active_storage_blob")
dump_file_path = File.join(Rails.root, "backup",active_storage_blobs_file)
dump_file = File.open(dump_file_path, "w")
dump_file.write(JSON.pretty_generate(ActiveStorage::Blob.all.as_json))
dump_file.close()
puts("...dump active_storage_attachment")
dump_file_path = File.join(Rails.root, "backup",
active_storage_attachments_file)
dump_file = File.open(dump_file_path, "w")
dump_file.write(JSON.pretty_generate(ActiveStorage::Attachment.all.as_json))
dump_file.close()
...load it back
puts("...load active_storage_blob")
dump_file_path = File.join(Rails.root, "backup", active_storage_blobs_file)
abort("File does not exist (" + dump_file_path + ") > abort <") unless File.exist?(dump_file_path)
load_json = JSON.parse(File.read(dump_file_path))
load_json.each do |j|
j = j.except("attachable_sgid")
result = ActiveStorage::Blob.create(j)
if (not result.errors.empty?)
puts(result.errors.full_messages.to_s)
puts(j.inspect)
exit(1)
end
end
puts("...load active_storage_attachment")
dump_file_path = File.join(Rails.root, "backup", active_storage_attachments_file)
abort("File does not exist (" + dump_file_path + ") > abort <") unless File.exist?(dump_file_path)
load_json = JSON.parse(File.read(dump_file_path))
load_json.each do |j|
result = ActiveStorage::Attachment.create(j)
if (not result.errors.empty?)
puts(result.errors.full_messages.to_s)
puts(j.inspect)
exit(1)
end
end

Getting shared path in controller with Rails and Capistrano

I have an upload system that performs several conversion operations on uploaded files (needs the real file paths to do them) and then stores paths of the resulting files.
Those files will be accessed later to create a zip file (again real path needed)
The problem with Capistrano is obviously when I store the file path using Rails.root.join('public', 'uploads', 'designer_user_uploaded') and then try to create my zip file like 10 days later and the release has changed, the stored file path no longer points to the correct location.
My directory is in the linked dirs for Capistrano. So the files are not lost but they just can't be retrieved anymore.
I'm not sure how I should handle this. I think it would be easy to solve by just doing something like File.join(shared_path, 'public', 'uploads', 'designer_user_uploaded') but I can't find how to get the shared path from controllers. Also this might not work in development.
I'm on Rails 4.2.6
output_folder = Rails.root.join('public', 'uploads', 'designer_user_uploaded')
FileUtils.mkdir_p(output_folder) unless File.directory?(output_folder)
file_name = sanitize_filename(Time.now.to_s + "_" + SecureRandom.uuid)
original_file_path = output_folder.join(change_file_extension(file_name, ext))
designer_file_path = ext == '.ai' || ext == '.eps' ?
output_folder.join(change_file_extension(file_name, '.svg')) : output_folder.join(change_file_extension(file_name, ext))
if ext == '.ai' || ext == '.eps'
copy_file(file.path, original_file_path)
copy_file(svg_path, designer_file_path)
#response[:original_file_path] = original_file_path
#response[:designer_file_path] = designer_file_path
#response[:file_name] = file_name + '.svg'
#response[:file_type] = "svg"
#response[:colors] = get_image_colors(original_file_path)
# Store created file paths for future access
#up = UserUpload.create(designer_path: designer_file_path, original_path: original_file_path)
puts #up.id
#response[:file_id] = #up.id
else
copy_file(file.path, designer_file_path)
#response[:original_file_path] = nil
#response[:designer_file_path] = designer_file_path
#response[:file_name] = file_name + ext
#response[:file_type] = ext == '.svg' ? 'svg' : "image"
#response[:colors] = get_image_colors(designer_file_path)
# Store created file path for future access
#up = UserUpload.create(designer_path: designer_file_path)
puts #up.id
#response[:file_id] = #up.id
end
# Embroidery conversion
is_embroidery = params[:is_embroidery].to_s.downcase == 'true'
if is_embroidery && (ext == '.svg' || ext == '.ai' || ext == '.eps')
embroidery_file_name = "embroidery_#{file_name}.svg"
embroidery_path = output_folder.join(embroidery_file_name)
Embroidery::EmbroideryConversionJob.perform_async(original_file_path, embroidery_path, #up)
#response[:designer_file_path] = embroidery_path
#response[:file_name] = embroidery_file_name
#response[:file_type] = "embroidery"
end
#response[:output_url] = '/uploads/designer_user_uploaded/'
file.close(true)

File deleted each time

I have a ruby controller
def new
counter = 1
fileW = File.new("query_output.txt", "w")
file = File.new("query_data.txt", "r")
while (line = file.gets)
puts "#{counter}: #{line}"
query = "select name,highway from planet_osm_line where name ilike '" +line+"'"
#output = PlanetOsmLine.connection.execute(query)
#output.each do |output|
fileW.write(output['highway'] + "\n")
end
counter = counter + 1
end
file.close
query = ""
#output = PlanetOsmLine.connection.execute(query)
end
So in this I am reading from a file like
%12th%main%
%100 feet%
%12th%main%
%12th%main%
%12th%main%
%100 feet%
In the ruby console I can see all the queries getting executed but in query_output.txt I only get the output of last query. What am I doing wrong here?
You use filemode w which will re-create the output file every time (so you will write into an empty file). Instead open your file as follows:
fileW = File.new("query_output.txt", "a")
a stands for append. It will open or create the file, and append at the back.
For more info concerning file-modes: http://pubs.opengroup.org/onlinepubs/009695399/functions/fopen.html

ZipRuby - Zipping files with duplicate names (clean code)

I have altered my code to prevent an error when zipping a number of files that have the same file name. I want to change it so that duplicate file names are incremented.
For example if you had three files called file.txt, then I want them to be file.txt, file_2.txt and file_3.txt
def zip(file_name)
files_added = []
ZipRuby::Archive.open(file_name, ZipRuby::CREATE) do |archive|
file_associations.sort_by { |fa| fa.created_at }.each do |fa|
attachment_file_name = fa.attachment_file_name
binding.pry
if files_added.include?(attachment_file_name)
n = 2
ext = File.extname(attachment_file_name)
base = File.basename(attachment_file_name, ext)
new_name = "#{base}_#{n}#{ext}"
while files_added.include? new_name
n += 1
new_name = "#{base}_#{n}#{ext}"
end
attachment_file_name = new_name
end
archive.add_buffer(attachment_file_name, fa.attachment.read)
files_added << attachment_file_name
end
end
end
The code above works but I am new to Ruby/Rails and it doesn't feel very Rubyist. Can anyone give any pointers for a refactor.

Ruby On Rails - how to rename currently uploaded file?

This is my method for uploading files:
name = file.original_filename
directory = "images/"
path = File.join(directory, name)
File.open(path, "wb") { |f| f.write(file.read) }
I need to rename the uploaded file - I want to give it a unique name. But how can I obtain the file name and the extension?
One way on how to rename the file is from the filename remove the extension (.jpg - remove last 4 chars), rename the file and then merge the name+extension.
But this is a bit dirty way. Is there something cleaner and more elegant?
A 'little' late but I put this answer for those who are still searching and get here.
photo = params[:photo]
name = photo.original_filename
directory = "public/uploads/photos"
path = File.join(directory, name)
uniq_name = (0...10).map { (65 + rand(26)).chr }.join
time_footprint = Time.now.to_formatted_s(:number)
File.open(path, "wb") do |file|
file.write(photo.read)
#uniq_path = File.join(directory, uniq_name + time_footprint + File.extname(file))
File.rename(file, #uniq_path)
end
I take the random string generation from How to generate a random string in Ruby. And set #uniq_path to use it on a create function after.
What about doing this?
File.rename(file, folder_path + "/" + new_name + File.extname(file))
For example, calling this script on the same folder of the file:
new_name = "TESTING"
File.open("test.txt") do |file|
File.rename(file, new_name + File.extname(file))
end
Will rename the file to: TESTING.txt

Resources