在运行时更改 ActiveStorage DirectDisk 服务配置 [英] Change ActiveStorage DirectDisk service configuration at runtime

查看:62
本文介绍了在运行时更改 ActiveStorage DirectDisk 服务配置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是 Rails 5.2 和 ActiveStorage 5.2.3 以及 DirectDiskService.

I am using Rails 5.2 and ActiveStorage 5.2.3 and DirectDiskService.

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

In order to have user uploads grouped nicely in directories and in order to be able to use CDNs as I please (eg CloudFlare or CloudFront or any other), I am trying to set up a method in ApplicationController that sets the (local) path for uploads, something like:

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 我有:

In config/initializers/active_storage.rb I have:

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 应用程序正在使用的那个上.

It does let me set the root on a new instance of the service but not on the one the Rails application is using.

我做错了什么?或者我如何完成这项工作?

What am I doing wrong? Or how do I get this done?

推荐答案

这里有一个肮脏的 hack,可帮助您将本地(磁盘)上传内容分类在 public/websites/domain_name/uploads 下.

Here's a dirty hack that helps you keep your local (disk) uploads grouped nice under public/websites/domain_name/uploads.

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

Step 1) install ActiveStorage DirectDisk service from here: 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 在技术上有效",但它缺少一些非常重要的功能,使其对大多数人无法使用,因此最终开发人员会倾听和调整;届时您可能需要重新访问此代码和所有上传的内容.

While ActiveRecord technically "works", it's missing some very important features that make it unusable for most people, so eventually the developer(s) will listen and adjust; at that time you may need to revisit this code AND all of your uploads.

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

The service attempts to "guess" the class name a blob is attached to since AS doesn't pass that, so it runs extra 2-3 queries against your database. If this bothers you just remove that bit and let it all go under websites/domain_name/uploads/all/

在某些情况下(例如变体,或带有 action_text 列的新记录),它无法确定附件记录及其类名,因此会在网站/域/上传/所有/...下上传.

In some cases (eg variants, or a new record with action_text column) it can't figure out the attachment record and its class name, so it will upload under websites/domain/uploads/all/...

这篇关于在运行时更改 ActiveStorage DirectDisk 服务配置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆