mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Defer Active Storage service configuration until use
This commit is contained in:
parent
986d3bf4c1
commit
709cee9c9a
7 changed files with 61 additions and 47 deletions
|
@ -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
|
||||
|
|
|
@ -38,7 +38,6 @@ module ActiveStorage
|
|||
|
||||
autoload :Attached
|
||||
autoload :Service
|
||||
autoload :ServiceRegistry
|
||||
autoload :Previewer
|
||||
autoload :Analyzer
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
32
activestorage/lib/active_storage/service/registry.rb
Normal file
32
activestorage/lib/active_storage/service/registry.rb
Normal 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
|
|
@ -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
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue