Изменение конфигурации службы ActiveStorage DirectDisk во время выполнения - PullRequest
0 голосов
/ 05 января 2020

Я использую 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 }

Это позволяет мне установить root на новый экземпляр службы, но не на тот, который использует приложение Rails.

Что я делаю неправильно ? Или как мне это сделать?

1 Ответ

0 голосов
/ 19 января 2020

Вот грязный хак, который помогает вам сгруппировать локальные (дисковые) загрузки в public / sites / 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) в конфигурации / инициализаторах /active_storage.rb

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

Шаг 5) in 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 запросов к вашей базе данных. Если это беспокоит, вы просто удаляете этот бит и оставляете все это go в веб-сайтах / имя_домена / uploads / all /

В некоторых случаях (например, варианты или новая запись со столбцом action_text) он не может отображаться запись вложения и его имя класса, поэтому он будет загружен в разделе веб-сайтов / домен / загрузки / все /...

...