【问题标题】:Change ActiveStorage DirectDisk service configuration at runtime在运行时更改 ActiveStorage DirectDisk 服务配置
【发布时间】:2020-01-05 18:07:56
【问题描述】:

我正在使用 Rails 5.2 和 ActiveStorage 5.2.3 和 DirectDiskService

为了让用户上传在目录中很好地分组,并且为了能够随意使用 CDN(例如 CloudFlare 或 CloudFront 或任何其他),我试图在 ApplicationController 中设置一个方法来设置(本地) 上传路径,例如:

class ApplicationController < ActionController::Base
  before_action :set_uploads_path

  # ...

private
  def set_upload_paths
     # this doesn't work
     ActiveStorage::Service::DirectDiskService.set_root p: "users/#{current_user.username}"
     # ... expecting the new root to become "public/users/yaddayadda"
  end
end

在 config/initializers/active_storage.rb 我有:

module SetDirectDiskServiceRoot
    def set_root(p:)
        @root = Rails.root.join("public", p)
        @public_root = p
        @public_root.prepend('/') unless @public_root.starts_with?('/')
    end
end

ActiveStorage::Service::DirectDiskService.module_eval { attr_writer :root }
ActiveStorage::Service::DirectDiskService.class_eval { include SetDirectDiskServiceRoot }

它确实让我可以在服务的新实例上设置根目录,但不能在 Rails 应用程序正在使用的实例上设置根目录。

我做错了什么?或者我该如何完成?

【问题讨论】:

    标签: ruby-on-rails rails-activestorage


    【解决方案1】:

    这是一个肮脏的 hack,可以帮助您将本地(磁盘)上传内容很好地分组在 public/websites/domain_name/uploads 下。

    步骤 1) 从此处安装 ActiveStorage DirectDisk 服务:https://github.com/sandrew/activestorage_direct_disk

    步骤 2)app/models/active_storage/current.rb

    class ActiveStorage::Current < ActiveSupport::CurrentAttributes #:nodoc:
      attribute :host
      attribute :domain_name
    end
    

    第 3 步) lib/set_direct_disk_service_path.rb

    module SetCurrentDomainName
        def set_domain_name(d)
            self.domain_name = d
        end
    end
    
    ActiveStorage::Current.class_eval { include SetCurrentDomainName }
    
    module SetDirectDiskServiceRoot
        def initialize(p:, public: false, **options)
            @root = Rails.root.join("public", p)
            @public_root = p
            @public_root.prepend('/') unless @public_root.starts_with?('/')
            puts options
        end
    
        def current_domain_name
            ActiveStorage::Current.domain_name
        end
    
        def folder_for(key)
            # original: File.join root, folder_for(key), key
            p = [ current_domain_name, "uploads", "all", key ]
            blob = ActiveStorage::Blob.find_by(key: key)
            if blob
                att = blob.attachments.first
                if att
                    rec = att.record
                    if rec
                        p = [ current_domain_name, "uploads", rec.class.name.split("::").last.downcase, rec.id.to_s, att.name, key ]
                    end
                end
            end
            return File.join p
        end
    end
    
    ActiveStorage::Service::DirectDiskService.module_eval { attr_writer :root }
    ActiveStorage::Service::DirectDiskService.class_eval { include SetDirectDiskServiceRoot }
    

    步骤 4)config/initializers/active_storage.rb

    require Rails.root.join("lib", "set_direct_disk_service_path.rb")
    

    步骤 5)app/controllers/application_controller.rb

    before_action :set_active_storage_domain_name
    
    # ...
    def set_active_storage_domain_name
        ActiveStorage::Current.domain_name = current_website.domain_name # or request.host
    end
    

    步骤 6)config/storage.yml

    development:
      service: DirectDisk
      root: 'websites_development'
    
    production:
      service: DirectDisk
      root: 'websites'
    

    缺点

    虽然 ActiveRecord 在技术上“有效”,但它缺少一些使其对大多数人无法使用的非常重要的功能,因此最终开发人员会倾听并调整;届时您可能需要重新访问此代码和所有上传的内容。

    该服务尝试“猜测”一个 blob 附加到的类名,因为 AS 没有通过它,因此它对您的数据库运行额外的 2-3 次查询。如果这让您感到困扰,您只需删除该位并将其全部放在 website/domain_name/uploads/all/ 下

    在某些情况下(例如变体,或带有 action_text 列的新记录)它无法确定附件记录及其类名,因此它将在 website/domain/uploads/all/... 下上传p>

    【讨论】:

      猜你喜欢
      • 2016-12-16
      • 1970-01-01
      • 1970-01-01
      • 2015-08-07
      • 1970-01-01
      • 1970-01-01
      • 2020-08-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多