Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test if a new file is sent with Active Storage in the model?

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.

like image 684
alex.bour Avatar asked Dec 05 '18 19:12

alex.bour


1 Answers

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.

like image 56
kasperite Avatar answered Nov 14 '22 17:11

kasperite