在运行时更改 ActiveStorage DirectDisk 服务配置
Change ActiveStorage DirectDisk service configuration at runtime
我正在使用 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 应用程序正在使用的实例上设置根目录。
我做错了什么?或者我该如何完成?
这里有一个肮脏的技巧,可以帮助您将本地(磁盘)上传的内容很好地分组在 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 "works",但它缺少一些非常重要的功能,这使得它对大多数人来说无法使用,因此最终开发人员会倾听并进行调整;届时您可能需要重新访问此代码和所有上传内容。
该服务尝试 "guess" blob 所附加的 class 名称,因为 AS 不通过该名称,因此它对您的数据库运行额外的 2-3 次查询。如果这让您感到困扰,您只需删除该位并将其全部放在 websites/domain_name/uploads/all/
下
在某些情况下(例如变体,或带有 action_text 列的新记录)它无法确定附件记录及其 class 名称,因此它将在 [=73] 下上传=]/...
我正在使用 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 应用程序正在使用的实例上设置根目录。
我做错了什么?或者我该如何完成?
这里有一个肮脏的技巧,可以帮助您将本地(磁盘)上传的内容很好地分组在 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 "works",但它缺少一些非常重要的功能,这使得它对大多数人来说无法使用,因此最终开发人员会倾听并进行调整;届时您可能需要重新访问此代码和所有上传内容。
该服务尝试 "guess" blob 所附加的 class 名称,因为 AS 不通过该名称,因此它对您的数据库运行额外的 2-3 次查询。如果这让您感到困扰,您只需删除该位并将其全部放在 websites/domain_name/uploads/all/
下在某些情况下(例如变体,或带有 action_text 列的新记录)它无法确定附件记录及其 class 名称,因此它将在 [=73] 下上传=]/...