Rails Active Storage 设置文件夹来存储文件

Posted

技术标签:

【中文标题】Rails Active Storage 设置文件夹来存储文件【英文标题】:Rails Active Storage set folder to store files 【发布时间】:2018-11-26 08:28:46 【问题描述】:

我正在使用 Active Storage 将文件存储在 Rails 5.2 项目中。我已将文件保存到 S3,但它们使用随机字符串文件名保存并直接保存到存储桶的根目录。我不介意随机文件名(我实际上更喜欢它用于我的用例),但希望将不同的附件组织到存储桶中的文件夹中。

我的模型使用has_one_attached :file。例如,我想指定将所有这些文件存储在 S3 内的 /downloads 文件夹中。我找不到任何有关如何设置这些路径的文档。

如果可能的话,像has_one_attached :file, folder: '/downloads' 这样的东西会很棒......

【问题讨论】:

How to specify a prefix when uploading to S3 using activestorage's direct upload?的可能重复 对于 S3 没关系,但如果你想切换到磁盘:***.com/questions/59602764/… 【参考方案1】:

截至目前ActiveStorage 不支持这种功能。请参阅此link。 has_one_attached 只接受namedependent

同样在 GitHub 的一个问题中,维护者明确提到他们显然不知道要实现类似 this 的东西。

我能想象的解决方法是,从前端上传文件,然后编写一个服务来更新active_storage_blob_statement中的key字段

【讨论】:

此链接现在可以使用 github.com/rails/rails/blob/master/activestorage/lib/…【参考方案2】:

没有官方方法可以改变由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

【讨论】:

你知道如何获取与 ActiveStorage::Blob 关联的应用的对象模型吗?【参考方案3】:
# 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

【讨论】:

【参考方案4】:

默认情况下活动存储不包含路径/文件夹功能,但您可以通过

覆盖该功能

model.file.attach(key: "downloads/filename", io: File.open(file), content_type: file.content_type, filename: "#file.original_filename")

这样做会将密钥与您要在 s3 子目录中存储文件的路径一起存储,并将其上传到您想要的确切位置。

【讨论】:

【参考方案5】:

使用 Cloudinary 服务的解决方案

如果您使用 Cloudinary,您可以在 storage.yml 上设置文件夹:

cloudinary:
  service: Cloudinary
  folder: <%= Rails.env %>

这样,Cloudinary 将根据您的 Rails 环境自动创建文件夹:

这是一个 long due issue,带有 Active Storage,Cloudinary 团队似乎已经解决了这个问题。感谢您的出色工作❤️

【讨论】:

【参考方案6】:

最终的解决方案是添加一个初始化器。您可以根据环境变量或 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

【讨论】:

以上是关于Rails Active Storage 设置文件夹来存储文件的主要内容,如果未能解决你的问题,请参考以下文章

无法加载 Rails.config.active_storage.service

无法使用 sequel-rails gem 安装 rails active_storage

markdown Rails + React build + Active Storage资产

Ruby on Rails - Active Storage - 如何只接受 pdf 和 doc?

如何使用 Active Storage Rails 上传到具有 AES256 加密(服务器端加密)的 AWS S3 存储桶?

Rails 5.2 Active Storage 添加自定义属性