How to move Active Storage data from one machine to another - ruby-on-rails

Because reasons we are trying to move a system from one machine to another one. It has several files in the storage directory. I rsynced it (using -a) to a local environment to see if everything works, but turns out not all the files are available, some of them raise an exception:
Errno::ENOENT (No such file or directory # rb_file_s_mtime - /path/to/project/storage/as/df/asdfasdfasdfasdfasdf):
Of course I checked the routes and they exists. I've been reading a bit about how Active Storage works and I maybe the URLs are getting invalidated for some reason, but why some files work? 🧐 Why the exception mentions mtime? And more importantly, how can I do the migration smoothly?
Thanks in advance

So the problem is actually the filesystems + Active Record names 😰 You can consider this a corner case: My local machine runs macOS, while the server runs Linux, so if I had folders Vf and VF on Linux, on macOS they become one (whichever is downloaded firs). Active Storage relies on case-sensitive filenames, and that's why some of the files work fine, but others are not found

Related

Errno::EACCES upon deleting a file (on Windows 10)

There are a number of similar questions, but none of the answers worked for me.
I'm running Rails 6.0.3.2, Ruby 2.6.6, and SQLite3 on Windows 10 version 2004 (19041.388). I followed the Getting Started guide on the official Rails site to install Ruby on Rails and and everything should be up to date.
I can delete the files normally, and I'm logged in with an administrator account — not that it should be necessary.
I'm new to Ruby and Rails, so detailed answers would be appreciated.
Code
Here's what causes the error:
def destroy
book = Book.find(params[:id])
begin
File.open(book.cover_url, 'w') do |f|
File.delete(f)
end
rescue Errno::ENOENT
end
book.destroy
redirect_to books_path
end
What this does it first delete the cover image for a book and then delete the book itself from the database.
Errors
The error screen:
If the picture doesn't load, here are the error messages:
Errno::EACCES in BooksController#destroy
Permission denied # apply2files - D:/Projects/Web/RoR/ecommerce/app/assets/images/covers/circles_scaling_anim_positioning.png
File.delete(f) is the culprit.
Attempted Solutions
The only actionable answer I could find for Windows was this,
which advocated adding a 'lib' gem, but it did not work at all.
I also tried changing file mode from 'w' to 'wb+', but that didn't
work either.
EDIT 2: As per Dave Newton's suggestion in the comments (if that's what he meant), I moved the image storage directory outside the 'app' folder; to 'public/uploads/covers'. It hasn't worked either.
EDIT 3: I copied the delete code to a new script in another directory entirely and tried it on a sample file. I got the same error. In other words, the problem is not with Rails but Ruby (or my OS).
I called rm on the file from the terminal and that worked just fine, so I don't know if it's a file permissions problem.
EDIT: I checked the file in question and though it still remains, it's 0 bytes large now, so I presume it was overwritten by empty data. However, the rest of the code that should've execuded on destroy — i.e. the destruction of the object in the databse — seems not to have run, because the object is still in there.
The file handling enforced by the operating system is different on Windows compared to most UNIXy operating systems (such as macOS, Linux, or the various BSDs).
On the UNIXy operating systems, the file entry in the filesystem is just a pointer to the "real" file stored on disk. There are other possible pointers, such as a file handle when the file is opened by a process, or a hardlink (i.e. a different filesystem entry pointing to the the exact same file). The file exists on disk as long as there is at least one valid pointer to that file.
As such, on UNIXy systems, you can delete (or rename / move) a file from the filesystem while it is opened from a process. The file itself will only actually be deleted once the last filehandle is closed.
Windows however is more strict in this regard by default. It will not allow to delete a file as long as there is any process which has a file handle on the file (i.e. if any process has opened the file). This explains why you can't delete the file while you have a filehandle on it
With that being said, since Ruby 2.3.0 there is a flag you can set when opening the file which instructs Windows to allow deleting (or moving) the file while it is opened:
# the flags for the normal 'w' mode
file_mode = IO::WRONLY | IO::CREAT | IO::TRUNC
# Add flags to allow deleting (or moving) the opened file
file_mode |= IO::BINARY | IO::SHARE_DELETE
File.open(book.cover_url, mode: file_mode) do |f|
File.delete(f)
end
Note that the IO::SHARE_DELETE flag is only taken into account for files opened in binary mode (rather than text mode) take this into account when working with this opened file. On UNIXy systems the IO::SHARE_DELETE is ignored.
There is some documentation of the various flags available.
As a final remark: I assume that your code is a shortened example where you have left out some code actually interacting with the opened file in addition to deleting it.
If all you want is to delete the file, there is no need to opened it first. Just delete it with File.delete(book.cover_url). Alternatively, if you you don't care for any errors (such as if the file doesn't exist in the first place, you can also use FileUtils.rm_f(book.cover_url).
Changed the code to this...
begin
File.delete(book.cover_url)
rescue Errno::ENOENT
end
...and it works now. No opening any files; just File.delete(URL).
If anyone knows why the original version didn't work, or why it's so commonly suggested, please post an answer or comment on this answer.

Rails 4: Issue Sending .txt files from local machine to Windows Share

I'm currently creating .csv files from a SQL view and writing to
#{Rails.root}/public/
which works no problem. In addition, I need to write these generated files to a Windows share in the form of:
\\NAME-APP.enterprise.company.com\Files
I've tried Net::SCP.upload, Net::SFTP.start, FileUtils, rsync, and even Dir.entries('share url here)` just to see if I can see anything in the folder, which generally results in
No such file or directory # dir_initialize
I can map my local computer to the Windows share point, in the form of:
smb://NAME-APP.enterprise.company.com/Files
but manually dragging and dropping to there isn't an acceptable solution in this case.
Feel like I've hit a wall and may be overlooking something. Have stumbled across this post but to no avail: How do I address a UNC path in Ruby on Windows?
Any advice on this is greatly appreciated.
Edit:
FileUtils.cp_r('/Volumes/Macintosh HD/Users/davidpardy/development/ror/sbb/oct31week/1a/FST-Export/public/1538791_new.txt', '\\\\NAME-APP\\Files')
doesn't return an error, but doesn't upload the .txt file to Files.
The solution is not to use FileUtils.cp_r(source_file, 'smb://...') because smb://... only represents the server address, not the mount folder on your filesystem.
In the terminal, run the mount command to find the path of the mount folder, which is what you'll use in ruby, e.g., FileUtils.cp_r(source_file, '/Volumes/mount_folder_here...').

IDA Pro: Reverse-Engineering Temp Storage

In the executable I am reverse-engineering, there are several references to a path in my D:\ drive. However, I do not have a D:\ drive connected. Is it possible that it creates a temporary storage site in the executable?
For example, there is a string:
D:\BuildAgent\...\bin\...\fileIWantToSee.jpg
IDA even believes that the symbol information is in the D drive, and attempts to look for it, to no avail. There are many instances of file references within these strings, and many of them end with a:
Line: **LINENUMBER**
Where would I go about trying to find where this storage is located? Thank you!
EDIT: Could it be in a specific section?
Is it possible that it creates a temporary storage site in the executable?
This is possible. There exists at least one product (http://www.boxedapp.com/, kind of our competitor :) that lets the application create such container -- the calls to file APIs are intercepted by the code added to the application by this product, and this added code handles specific paths in a different way (emulating file operations), letting all other calls go to Windows API.

Is it good way to use /tmp in application for storing temporary files?

In my application, we store temporary images generated from PDF in /tmp/pdf_images folder. Is it a standard practice? Or It's not recommended to use of /tmp from application code?
Assuming you're on linux or MacOS, this directory is just there for this.
Be sure to have them automatically deleted at closing of your application.
And note that they may be purged by the OS or the user (directly or not) at any moment when your application isn't running. And generally, it's totally cleaned at reboot (and every 3 days on MacOS).

How to find out the name of the common documents folder on a network machine

Given that I am executing an EXE file (D2006 app) on a machine across the network, how can I get the pathname to the commondocs folder on that machine, given that the EXE might have been invoked from a UNC shortcut or a mapped drive letter shortcut, and the platform of the remote machine is not necessarily known (but will be >= WinXP)?
The situation is where the client has a large number of dispersed machines, and they can't be bothered installing my app on all the PC's. So what they do is install the executable somewhere on the network and give everybody a shortcut to that. This already seems to suit them fine and there are no issues there.
At their request, I made the app read the settings from an INI file placed in the same folder as the executable. I can only assume they have configured things so that all the users can write to that folder so that the INI file can be saved back.
However, I want to change it so that the INI file is read and saved to somewhere in the commondocs folder tree on the remote machine, so that they don't need to provide write access to a Program files folder.
The machine that's running your program is the only machine you have access to. The machine where your program is stored is irrelevant. It's just a disk drive. It might not be running Windows. It might even be a NAS that's hardly running anything at all.
If the customer wants the common-documents folder of the file server to act as the common-documents folder for everyone on all the client systems, then get the sysadmin to configure a shared folder on the server and then configure the clients to use that remote folder as their common-documents folder. There is no special programming required on your part for that.
To get the common-documents folder of the machine your program is running on, you can call any of various API functions, including ShGetFolderPath. The CSIDL value you need is CSIDL_COMMON_DOCUMENTS. If you call SHGetKnownFolderPath instead, use FOLDERID_PublicDocuments.

Resources