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
|
has_secure_token :key, length: MINIMUM_TOKEN_LENGTH
|
||||||
store :metadata, accessors: [ :analyzed, :identified ], coder: ActiveRecord::Coders::JSON
|
store :metadata, accessors: [ :analyzed, :identified ], coder: ActiveRecord::Coders::JSON
|
||||||
|
|
||||||
|
class_attribute :services, default: {}
|
||||||
class_attribute :service
|
class_attribute :service
|
||||||
|
|
||||||
has_many :attachments
|
has_many :attachments
|
||||||
|
@ -49,8 +50,8 @@ class ActiveStorage::Blob < ActiveRecord::Base
|
||||||
validates :service_name, presence: true
|
validates :service_name, presence: true
|
||||||
|
|
||||||
validate do
|
validate do
|
||||||
if service_name_changed? && service_name
|
if service_name_changed? && service_name.present?
|
||||||
ActiveStorage::ServiceRegistry.fetch(service_name) do
|
services.fetch(service_name) do
|
||||||
errors.add(:service_name, :invalid)
|
errors.add(:service_name, :invalid)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -266,7 +267,7 @@ class ActiveStorage::Blob < ActiveRecord::Base
|
||||||
|
|
||||||
# Returns an instance of service, which can be configured globally or per attachment
|
# Returns an instance of service, which can be configured globally or per attachment
|
||||||
def service
|
def service
|
||||||
ActiveStorage::ServiceRegistry.fetch(service_name)
|
services.fetch(service_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -38,7 +38,6 @@ module ActiveStorage
|
||||||
|
|
||||||
autoload :Attached
|
autoload :Attached
|
||||||
autoload :Service
|
autoload :Service
|
||||||
autoload :ServiceRegistry
|
|
||||||
autoload :Previewer
|
autoload :Previewer
|
||||||
autoload :Analyzer
|
autoload :Analyzer
|
||||||
|
|
||||||
|
|
|
@ -165,13 +165,13 @@ module ActiveStorage
|
||||||
|
|
||||||
private
|
private
|
||||||
def validate_service_configuration(association_name, service)
|
def validate_service_configuration(association_name, service)
|
||||||
return unless service
|
if service.present?
|
||||||
|
ActiveStorage::Blob.services.fetch(service) do
|
||||||
ServiceRegistry.fetch(service) do
|
|
||||||
raise ArgumentError, "Cannot configure service :#{service} for #{name}##{association_name}"
|
raise ArgumentError, "Cannot configure service :#{service} for #{name}##{association_name}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def attachment_changes #:nodoc:
|
def attachment_changes #:nodoc:
|
||||||
@attachment_changes ||= {}
|
@attachment_changes ||= {}
|
||||||
|
|
|
@ -14,6 +14,8 @@ require "active_storage/previewer/video_previewer"
|
||||||
require "active_storage/analyzer/image_analyzer"
|
require "active_storage/analyzer/image_analyzer"
|
||||||
require "active_storage/analyzer/video_analyzer"
|
require "active_storage/analyzer/video_analyzer"
|
||||||
|
|
||||||
|
require "active_storage/service/registry"
|
||||||
|
|
||||||
require "active_storage/reflection"
|
require "active_storage/reflection"
|
||||||
|
|
||||||
module ActiveStorage
|
module ActiveStorage
|
||||||
|
@ -101,10 +103,25 @@ module ActiveStorage
|
||||||
|
|
||||||
initializer "active_storage.services" do
|
initializer "active_storage.services" do
|
||||||
ActiveSupport.on_load(:active_storage_blob) do
|
ActiveSupport.on_load(:active_storage_blob) do
|
||||||
if config_choice = Rails.configuration.active_storage.service
|
configs = Rails.configuration.active_storage.service_configurations ||=
|
||||||
ActiveStorage::Blob.service = ActiveStorage::ServiceRegistry.fetch(config_choice) do
|
begin
|
||||||
raise ArgumentError, "Cannot load `Rails.application.config.active_storage.service`:\n#{config_choice}"
|
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
|
||||||
|
|
||||||
|
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
|
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
|
end
|
||||||
|
|
||||||
def with_service(service_name)
|
def with_service(service_name)
|
||||||
service = ActiveStorage::ServiceRegistry.fetch(service_name)
|
|
||||||
previous_service = ActiveStorage::Blob.service
|
previous_service = ActiveStorage::Blob.service
|
||||||
ActiveStorage::Blob.service = service
|
ActiveStorage::Blob.service = ActiveStorage::Blob.services.fetch(service_name)
|
||||||
|
|
||||||
yield
|
yield
|
||||||
ensure
|
ensure
|
||||||
|
|
Loading…
Reference in a new issue