Referencing this PR: https://github.com/rails/rails/commit/4dba136c83cc808282625c0d5b195ce5e0bbaa68
We can now specify a blob key when using the traditional attach method. However, I cannot figure out how to specify the key when using direct uploads. The direct upload method was also updated in this PR, so I’m hoping I’m missing something.
As far as I can tell, if I want to send in a custom key such as user.company/public/filename using direct uploads I…can’t? I’d have to hook in here: https://github.com/rails/rails/blob/b5dac96b59a582c7968b0c33d6ff39d1cfc336dc/activestorage/app/assets/javascripts/activestorage.js#L690var blob = new BlobRecord(_this.file, checksum, _this.url);
Even if I send in a this.key to my direct uploads controller, I don’t want to change the call to BlobRecord and I don’t want to patch activestorage.js b/c that will certainly cause trouble in the future.
I can override key in blob.rb, but I want to prefix based on user.company, so I need to send in the user details somehow.
TLDR:
Can I send a key variable with this new PR via direct uploads? I know this was previously not how ASt was designed, but the above PR makes me hopeful there may be a way.
Note: On Rails 6.0
I’ve sorted out that to enable changing the key on direct uploads you can’t just override key on blob.rb because the key is being set beforedef key is called. By the time you hit the def key method self[:key] has already been set by generate_unique_secure_token which IIRC is called from activerecord. Anyway, since I’m only using direct uploads I patched create_before_direct_upload! to force the key in the format I want.
ActiveRecord now has a thing called has_secure_token, which ActiveStorage is using on Blob. This has_secure_token is setting a before_create with the following code:
When it’s being called like this, the self[:key] method only sets it if it doesn’t exist
ActiveStorage::Blob.class_eval do
def key
self[:key] ||= 'your custom key'
end
end
I fixed this by doing the following in config/application.rb
class Application < Rails::Application
# ...
# ...
# ...
Rails.application.config.to_prepare do
require 'active_storage/blob'
class ActiveStorage::Blob
def self.generate_unique_secure_token(length: MINIMUM_TOKEN_LENGTH)
gust = SecureRandom.base36(length)
epoch = Time.now.to_i.to_s
checksum = Digest::MD5.hexdigest(gust + epoch)
folder = checksum.chars.first(9).each_slice(3).to_a.map(&:join).join('/')
"#{folder}/#{gust}"
end
end
# Rails 5 doesn't have secure_token for Blob, so this will monkey patch it
ActiveStorage::Blob.class_eval do
def key
self[:key] ||= generate_key_with_folder
end
def generate_key_with_folder
gust = self.class.generate_unique_secure_token
epoch = Time.now.to_i.to_s
checksum = Digest::MD5.hexdigest(gust + epoch)
folder = checksum.chars.first(9).each_slice(3).to_a.map(&:join).join('/')
"#{folder}/#{gust}"
end
end
end
end
Yes, there are already easier solutions. But for this, it is better to contact the Ruby on rails developers in Factor Dedicated Teams. I work with them myself.