Defer Active Storage service configuration until use

This commit is contained in:
George Claghorn 2019-11-08 15:03:42 -05:00 committed by GitHub
parent 986d3bf4c1
commit 709cee9c9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 61 additions and 47 deletions

View File

@ -32,6 +32,7 @@ class ActiveStorage::Blob < ActiveRecord::Base
has_secure_token :key, length: MINIMUM_TOKEN_LENGTH
store :metadata, accessors: [ :analyzed, :identified ], coder: ActiveRecord::Coders::JSON
class_attribute :services, default: {}
class_attribute :service
has_many :attachments
@ -49,8 +50,8 @@ class ActiveStorage::Blob < ActiveRecord::Base
validates :service_name, presence: true
validate do
if service_name_changed? && service_name
ActiveStorage::ServiceRegistry.fetch(service_name) do
if service_name_changed? && service_name.present?
services.fetch(service_name) do
errors.add(:service_name, :invalid)
end
end
@ -266,7 +267,7 @@ class ActiveStorage::Blob < ActiveRecord::Base
# Returns an instance of service, which can be configured globally or per attachment
def service
ActiveStorage::ServiceRegistry.fetch(service_name)
services.fetch(service_name)
end
private

View File

@ -38,7 +38,6 @@ module ActiveStorage
autoload :Attached
autoload :Service
autoload :ServiceRegistry
autoload :Previewer
autoload :Analyzer

View File

@ -165,10 +165,10 @@ module ActiveStorage
private
def validate_service_configuration(association_name, service)
return unless service
ServiceRegistry.fetch(service) do
raise ArgumentError, "Cannot configure service :#{service} for #{name}##{association_name}"
if service.present?
ActiveStorage::Blob.services.fetch(service) do
raise ArgumentError, "Cannot configure service :#{service} for #{name}##{association_name}"
end
end
end
end

View File

@ -14,6 +14,8 @@ require "active_storage/previewer/video_previewer"
require "active_storage/analyzer/image_analyzer"
require "active_storage/analyzer/video_analyzer"
require "active_storage/service/registry"
require "active_storage/reflection"
module ActiveStorage
@ -101,10 +103,25 @@ module ActiveStorage
initializer "active_storage.services" do
ActiveSupport.on_load(:active_storage_blob) do
if config_choice = Rails.configuration.active_storage.service
ActiveStorage::Blob.service = ActiveStorage::ServiceRegistry.fetch(config_choice) do
raise ArgumentError, "Cannot load `Rails.application.config.active_storage.service`:\n#{config_choice}"
configs = Rails.configuration.active_storage.service_configurations ||=
begin
config_file = Pathname.new(Rails.root.join("config/storage.yml"))
raise("Couldn't find Active Storage configuration in #{config_file}") unless config_file.exist?
require "yaml"
require "erb"
YAML.load(ERB.new(config_file.read).result) || {}
rescue Psych::SyntaxError => e
raise "YAML syntax error occurred while parsing #{config_file}. " \
"Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
"Error: #{e.message}"
end
ActiveStorage::Blob.services = ActiveStorage::Service::Registry.new(configs)
if config_choice = Rails.configuration.active_storage.service
ActiveStorage::Blob.service = ActiveStorage::Blob.services.fetch(config_choice)
end
end
end

View File

@ -0,0 +1,32 @@
# frozen_string_literal: true
module ActiveStorage
class Service::Registry #:nodoc:
def initialize(configurations)
@configurations = configurations.deep_symbolize_keys
@services = {}
end
def fetch(name)
services.fetch(name.to_sym) do |key|
if configurations.include?(key)
services[key] = configurator.build(key)
else
if block_given?
yield key
else
raise KeyError, "Missing configuration for the #{key} Active Storage service. " \
"Configurations available for the #{configurations.keys.to_sentence} services."
end
end
end
end
private
attr_reader :configurations, :services
def configurator
@configurator ||= ActiveStorage::Service::Configurator.new(configurations)
end
end
end

View File

@ -1,34 +0,0 @@
# frozen_string_literal: true
module ActiveStorage
class ServiceRegistry #:nodoc:
class << self
def fetch(service_name, &block)
services.fetch(service_name.to_s, &block)
end
private
def services
@services ||= configs.keys.each_with_object({}) do |service_name, hash|
hash[service_name] = ActiveStorage::Service.configure(service_name, configs)
end
end
def configs
Rails.configuration.active_storage.service_configurations ||= begin
config_file = Pathname.new(Rails.root.join("config/storage.yml"))
raise("Couldn't find Active Storage configuration in #{config_file}") unless config_file.exist?
require "yaml"
require "erb"
YAML.load(ERB.new(config_file.read).result) || {}
rescue Psych::SyntaxError => e
raise "YAML syntax error occurred while parsing #{config_file}. " \
"Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
"Error: #{e.message}"
end
end
end
end
end

View File

@ -103,9 +103,8 @@ class ActiveSupport::TestCase
end
def with_service(service_name)
service = ActiveStorage::ServiceRegistry.fetch(service_name)
previous_service = ActiveStorage::Blob.service
ActiveStorage::Blob.service = service
ActiveStorage::Blob.service = ActiveStorage::Blob.services.fetch(service_name)
yield
ensure