Reputation: 2964
In my Rails model, I have this code to force the filename to be changed when uploading:
before_save :set_filename
def set_filename
if file.attached?
self.file.blob.update(filename: "#{new_file_name()}.#{self.file.blob.content_type.split('/')[1]}")
end
end
The problem is the filename is changed even if a new file is not sent in the form (when editing).
My attachement is simply named file:
# active storage
has_one_attached :file
How to really test that a new file is attached when uploading ?
Thanks,
EDIT: more clarifications
I have a form with a file_field. I want to test if a new file is sent via the form, when I add or modify the object of the form.
My model is called Image and the attached file is called file.
class Image
has_one_attached :file
end
I want to change the filename every time a new file is sent via the form, and not of course is the file_field stays empty.
Upvotes: 5
Views: 6470
Reputation: 4851
I have just solved this problem (or something very similar) using the blob
record associated with the attachment.
Since the blob
is an ActiveStorage::Blob
, which is derived from ActiveRecord::Base
, you can use the "dirty" methods on it to see if it has been changed. e.g.
def set_filename
if file.attached? && (file_blob.has_changes_to_save? || file_blob.saved_changes?)
self.file.blob.update(filename: "#{new_file_name()}.#{self.file.blob.content_type.split('/')[1]}")
end
end
Depending on where in the lifecycle set_filename
is called from, there may only be a need to check one of has_changes_to_save?
or saved_changes?
. Since, in your example, you're calling this in before_save
, you would only need file_blob.has_changes_to_save?
Upvotes: 1
Reputation: 2478
You can use new_record? to check if file
is new ie:
def set_filename
if file.attached? && file.new_record?
self.file.blob.update(filename: "#{new_file_name()}.#{self.file.blob.content_type.split('/')[1]}")
end
end
Alternatively, use before_create
instead of before_save
so that set_name
only runs when uploading new file.
Updated
Interestingly, ActiveStorage handles blob change outside model hooks. Apparently, it doesn't even support validation right now. There's no way to verify blob has changed as its state is not persisted anywhere. If you peek into rails log, notice rails purge old blob as soon as a new one is added.
Few options I can think of:
1.Update filename in controller eg:
original_name = params[:file].original_name
params[:file].original_name = # your logic goes here
2.Store blob file name in parent model and compare in before_save
.
def set_filename
if file.attached? && file.blob.filename != self.old_filename
self.file.blob.update(filename: "#{new_file_name()}.#{self.file.blob.content_type.split('/')[1]}")
end
end
None of these solutions are ideal but hope they give you some ideas.
Upvotes: 5