Rails Active Storage 设置存放文件的文件夹
Rails Active Storage set folder to store files
我正在使用 Active Storage 将文件存储在 Rails 5.2 项目中。我已经将文件保存到 S3,但它们使用随机字符串文件名保存并直接保存到存储桶的根目录。我不介意随机文件名(我实际上更喜欢它用于我的用例)但希望将不同的附件组织到存储桶中的文件夹中。
我的模型使用 has_one_attached :file
。例如,我想指定将所有这些文件存储在 S3 的 /downloads
文件夹中。我找不到任何关于如何设置这些路径的文档。
如果可能的话 has_one_attached :file, folder: '/downloads'
这样的东西会很棒...
截至目前 ActiveStorage
不支持此类功能。参考这个link。 has_one_attached
只接受 name
和 dependent
.
同样在 GitHub 问题之一中,维护者明确提到他们显然不知道要实现 this.
这样的东西
我能想到的解决方法是,从前端上传文件,然后编写一个服务来更新 active_storage_blob_statement
中的 key
字段
官方没有修改路径的方法,由ActiveStorage::Blob#key
决定,源码为:
def key
self[:key] ||= self.class.generate_unique_secure_token
end
而ActieStorage::Blog.generate_unique_secure_token
是
def generate_unique_secure_token
SecureRandom.base36(28)
end
因此,解决方法是重写 key
方法,如下所示:
# config/initializers/active_storage.rb
ActiveSupport.on_load(:active_storage_blob) do
def key
self[:key] ||= "my_folder/#{self.class.generate_unique_secure_token}"
end
end
别担心,这不会影响现有文件。但是你必须小心 ActiveStorage 是非常新的东西,它的源代码是变体。升级Rails版本时,提醒自己看看是不是这个补丁导致的问题。
您可以从这里阅读 ActiveStorage 源代码:https://github.com/rails/rails/tree/master/activestorage
# config/initializers/active_storage.rb
ActiveSupport.on_load(:active_storage_blob) do
def key
sql_find_order_id = "select * from active_storage_attachments where blob_id = #{self.id}"
active_storage_attachment = ActiveRecord::Base.connection.select_one(sql_find_order_id)
# this variable record_id contains the id of object association in has_one_attached
record_id = active_storage_attachment['record_id']
self[:key] = "my_folder/#{self.class.generate_unique_secure_token}"
self.save
self[:key]
end
end
默认情况下,Active Storage 不包含 path/folder 功能,但您可以通过
覆盖该功能
model.file.attach(key: "downloads/filename", io: File.open(file), content_type: file.content_type, filename: "#{file.original_filename}")
这样做会将密钥与您要在 s3 子目录中存储文件的路径一起存储,并将其上传到您想要的确切位置。
使用 Cloudinary 服务的解决方案
如果您使用的是 Cloudinary,则可以在 storage.yml 上设置文件夹:
cloudinary:
service: Cloudinary
folder: <%= Rails.env %>
这样,Cloudinary 将根据您的 Rails 环境自动创建文件夹:
这是一个带有 Active Storage 的 long due issue,Cloudinary 团队似乎已经解决了这个问题。感谢您的出色工作❤️
最终的解决方案是添加一个初始化程序。您可以根据环境变量或您的 Rails.env
:
添加前缀
# config/initializer/active_storage.rb
Rails.configuration.to_prepare do
ActiveStorage::Blob.class_eval do
before_create :generate_key_with_prefix
def generate_key_with_prefix
self.key = if prefix
File.join prefix, self.class.generate_unique_secure_token
else
self.class.generate_unique_secure_token
end
end
def prefix
ENV["SPACES_ROOT_FOLDER"]
end
end
end
它与此完美配合。其他人建议使用 Shrine.
感谢这个伟大的解决方法: https://dev.to/drnic/how-to-isolate-your-rails-blobs-in-subfolders-1n0c
我正在使用 Active Storage 将文件存储在 Rails 5.2 项目中。我已经将文件保存到 S3,但它们使用随机字符串文件名保存并直接保存到存储桶的根目录。我不介意随机文件名(我实际上更喜欢它用于我的用例)但希望将不同的附件组织到存储桶中的文件夹中。
我的模型使用 has_one_attached :file
。例如,我想指定将所有这些文件存储在 S3 的 /downloads
文件夹中。我找不到任何关于如何设置这些路径的文档。
如果可能的话 has_one_attached :file, folder: '/downloads'
这样的东西会很棒...
截至目前 ActiveStorage
不支持此类功能。参考这个link。 has_one_attached
只接受 name
和 dependent
.
同样在 GitHub 问题之一中,维护者明确提到他们显然不知道要实现 this.
这样的东西我能想到的解决方法是,从前端上传文件,然后编写一个服务来更新 active_storage_blob_statement
key
字段
官方没有修改路径的方法,由ActiveStorage::Blob#key
决定,源码为:
def key
self[:key] ||= self.class.generate_unique_secure_token
end
而ActieStorage::Blog.generate_unique_secure_token
是
def generate_unique_secure_token
SecureRandom.base36(28)
end
因此,解决方法是重写 key
方法,如下所示:
# config/initializers/active_storage.rb
ActiveSupport.on_load(:active_storage_blob) do
def key
self[:key] ||= "my_folder/#{self.class.generate_unique_secure_token}"
end
end
别担心,这不会影响现有文件。但是你必须小心 ActiveStorage 是非常新的东西,它的源代码是变体。升级Rails版本时,提醒自己看看是不是这个补丁导致的问题。
您可以从这里阅读 ActiveStorage 源代码:https://github.com/rails/rails/tree/master/activestorage
# config/initializers/active_storage.rb
ActiveSupport.on_load(:active_storage_blob) do
def key
sql_find_order_id = "select * from active_storage_attachments where blob_id = #{self.id}"
active_storage_attachment = ActiveRecord::Base.connection.select_one(sql_find_order_id)
# this variable record_id contains the id of object association in has_one_attached
record_id = active_storage_attachment['record_id']
self[:key] = "my_folder/#{self.class.generate_unique_secure_token}"
self.save
self[:key]
end
end
默认情况下,Active Storage 不包含 path/folder 功能,但您可以通过
覆盖该功能model.file.attach(key: "downloads/filename", io: File.open(file), content_type: file.content_type, filename: "#{file.original_filename}")
这样做会将密钥与您要在 s3 子目录中存储文件的路径一起存储,并将其上传到您想要的确切位置。
使用 Cloudinary 服务的解决方案
如果您使用的是 Cloudinary,则可以在 storage.yml 上设置文件夹:
cloudinary:
service: Cloudinary
folder: <%= Rails.env %>
这样,Cloudinary 将根据您的 Rails 环境自动创建文件夹:
这是一个带有 Active Storage 的 long due issue,Cloudinary 团队似乎已经解决了这个问题。感谢您的出色工作❤️
最终的解决方案是添加一个初始化程序。您可以根据环境变量或您的 Rails.env
:
# config/initializer/active_storage.rb
Rails.configuration.to_prepare do
ActiveStorage::Blob.class_eval do
before_create :generate_key_with_prefix
def generate_key_with_prefix
self.key = if prefix
File.join prefix, self.class.generate_unique_secure_token
else
self.class.generate_unique_secure_token
end
end
def prefix
ENV["SPACES_ROOT_FOLDER"]
end
end
end
它与此完美配合。其他人建议使用 Shrine.
感谢这个伟大的解决方法: https://dev.to/drnic/how-to-isolate-your-rails-blobs-in-subfolders-1n0c