Ruby On Rails - how to rename currently uploaded file? - ruby-on-rails

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

Related

how to read a file from blob and save it to public folder in rails

i am reading a pdf file from blob and saving it to local folder
#doc = Document.find(params[:id])
blob = #doc.docs.first.blob
ActiveStorage::Downloader.new(blob.service).open(blob.key, checksum: blob.checksum) do |tempFile|
temppdf = Tempfile.new ["mypdf", ".pdf"]
pathpdf = "app/assets/images/" + current_account.email+'.pdf'
tempFile.save(pathpdf)
end
You can use ActiveStorage::Blob#open to steam the file directly to disk circumventing the tempfile:
#doc = Document.find(params[:id])
blob = #doc.docs.first.blob
# app/assets certainly isn't a public path...
fn = Rails.root.join('public', 'uploads', 'mypdf.pdf')
File.open(fn, "wb+") do |file|
blob.download { |chunk| file.write(chunk) }
end

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

I want to change the file name after downloading the zip file

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

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-Reading a specific bash-script file from ruby file

#practice.rb
$TENANT=gets.chomp('/\p{Alnum}/')
$first = $TENANT.slice(0,1).capitalize
$second = $TENANT.slice(1..-1)
EXPORT_PASSWORD="Export-"+ $first + $second.chomp + "!"
EXPORT_FILENAME=$TENANT.chomp + ".xar"
file = File.open("/Users/..../input/exporttenant.rb", "r")
contents = file.read
puts content
output = File.open(/.../input/$TENANT.txt, "w")
$TENANT=tenant_name
file = File.open("/data/workday/wmu/input/exportTenant.properties", "r")
$line = file.readlines.select{|line| line.match('DS_ENTRY_OMS_SERVER')}
file.close
output=File.open("/data/workday/wmu/input/#{$TENANT}".chomp, 'w')
output.puts "TENANT_NAME=#{$TENANT}"
output.puts "EXPORT_PASSWORD=#{$PASSWORD}"
output.puts "EXPORT_FILENAME=#{FILENAME}"
output.puts "EXPORT_WITHOUT_TAR=N"
output.puts "BYPASS_BLOB=N"
output.puts $line
output.close
print "Export tenant created for the #{$TENANT}\n"
I have created one file by the name(wandarar.sh-written in bash).The wanda.sh file has commands.I want to run the wandarar.sh file from another file(practice.rb).
I want to include the same functionality what wandarar.sh file have into the practice.rb file. How can I run this.Can someone help me with this ?
Basically, you are getting an array, select a line which is matched your criteria.
file = File.open('/home/username/Documents/file.txt', 'r')
puts file.readlines.select{|line| line.match('DS_ENTRY')}
file.close
I think what you are looking for is the .grep method, try this:
file_name = "put your file name here"
lines = File.readlines(file_name)
lines.grep(/DS_ENTRY\((.*)\)/)
File.open($1, "w") { |f| f.puts "file content" }

Resources