TL;DR Use user.update!(remove_avatar: true)
to delete attachments outside of forms. This will have the same behavior as if you were in a form.
As you know, Carrierwave file attachments work by mounting an Uploader
class to an attribute of the model. Though the database field holds the file name as string, calling the attribute will always return the uploader, no matter if a file is attached or not. (Side note: use #present?
on the uploader to check if the file exists.)
class User < ApplicationRecord
mount :avatar, AvatarUploader
end
Now there are several ways to delete an attached file. The invocations do not have the same effect (while each is correct in its domain):
remove_avatar
to true
and saving:
user.remove_avatar = true
user.save!
# or even shorter
user.update!(remove_avatar: true)
This lives in the ActiveRecord domain. It will delete the file AND empty the database field.#remove_avatar!
Show archive.org snapshot
method Carrierwave patches onto the model
user.remove_avatar!
user.save!
The method #remove_avatar!
on the model lives in the ActiveRecord domain. It will delete the file AND empty the database field. Subsequent calls to avatar.present?
will return false
.u = User.last
u.avatar.present? # => true
User.find_each do |u|
u.remove_avatar!
u.save!
end
u.avatar.present? # => true
u.reload.avatar.present? # => true
User.find(u.id).avatar.present? # => false
Note
#remove_avatar!
itself does not save. Carrierwave internally calls this method as andafter_commit
callback, so it saves to the DB first and removes the file afterwards. If you call this method manually and then save, you risk that your change to the DB will fail after you already deleted the file.
#remove!
Show archive.org snapshot
method from the uploader:
user.avatar.remove!
NOTE: #remove!
on the uploader lives in the "file storage" domain. It will delete the file, but leave the database field untouched, so the uploader will believe it is still there. Subsequent calls to avatar.present?
will return true
.Unless you deal with low-level logic and have good reasons to do otherwise, probably stick with option 1.