Skip to content

Commit

Permalink
Add support for ActiveStorage model service configuration
Browse files Browse the repository at this point in the history
Fixes #558
  • Loading branch information
const-cloudinary authored Sep 5, 2024
1 parent d31de32 commit 4f0b6ac
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 11 deletions.
35 changes: 33 additions & 2 deletions lib/active_storage/service/cloudinary_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ module CloudinaryHelper
alias cloudinary_url_internal_original cloudinary_url_internal

def cloudinary_url_internal(source, options = {})
if defined?(ActiveStorage::Blob.service.public_id) && options.fetch(:type, "").to_s != "fetch"
source = ActiveStorage::Blob.service.public_id(source)
service_instance, options = ActiveStorage::Service::CloudinaryService.fetch_service_instance_and_config(source, options)
service_instance ||= ActiveStorage::Blob.service

if defined?(service_instance.public_id) && options.fetch(:type, "").to_s != "fetch"
source = service_instance.public_id(source)
end

cloudinary_url_internal_original(source, options)
end
end
Expand Down Expand Up @@ -190,6 +194,33 @@ def public_id(key, filename = nil, content_type = '')
full_public_id_internal(public_id)
end

def self.fetch_service_instance_and_config(source, options)
return [nil, options] unless defined?(ActiveStorage::BlobKey) && source.is_a?(ActiveStorage::BlobKey) &&
source.respond_to?(:attributes) && source.attributes.key?(:service_name)

service_name = source.attributes[:service_name]

begin
service_instance = ActiveStorage::Blob.services.fetch(service_name.to_sym)

unless service_instance.instance_of?(ActiveStorage::Service::CloudinaryService)
Rails.logger.error "Expected service instance #{service_instance.class.name} to be of type ActiveStorage::Service::CloudinaryService."
return [nil, options]
end

service_config = Rails.application.config.active_storage.service_configurations.fetch(service_name)
options = service_config.merge(options)
rescue NameError => e
Rails.logger.error "Failed to retrieve the service instance for #{service_name}: #{e.message}"
return [nil, options]
rescue => e
Rails.logger.error "An unexpected error occurred: #{e.message}"
return [nil, options]
end

[service_instance, options]
end

private

def api_uri(action, options)
Expand Down
14 changes: 14 additions & 0 deletions spec/active_storage/dummy/config/storage.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
local:
service: Disk
root: <%= Rails.root.join("storage") %>

cloudinary:
service: Cloudinary
type: authenticated
tags:
- ActiveStorageTestTag
folder: active_storage_test_folder

cloudinary2:
service: Cloudinary
tags:
- ActiveStorageTestTag2
folder: active_storage_test_folder2
cloud_name: test2
38 changes: 37 additions & 1 deletion spec/active_storage/service/cloudinary_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
AS_TAG = "active_storage_" + SUFFIX
BASENAME = File.basename(TEST_IMG, '.*')

CONFIGURATION_PATH = Pathname.new(File.expand_path("service/configurations.yml", __dir__))
CONFIGURATION_PATH = Pathname.new(File.expand_path("dummy/config/storage.yml", __dir__))
SERVICE = ActiveStorage::Service.configure(:cloudinary, SERVICE_CONFIGURATIONS)

TEST_IMG_PATH = Pathname.new(TEST_IMG)
Expand Down Expand Up @@ -251,3 +251,39 @@
end
end

describe 'Active Storage CloudinaryHelper' do
before :all do
ActionView::Base.send :include, CloudinaryHelper
end

let(:helper) {
ActionView::Base.new(ActionView::LookupContext.new([]), {}, nil)
}
let(:custom_service_key) {
ActiveStorage::BlobKey.new key: SecureRandom.base58(24), filename: BASENAME, service_name: 'cloudinary2'
}
let(:conf) {
SERVICE_CONFIGURATIONS[:cloudinary2]
}

it 'should respect custom service_name in cloudinary_url' do
url = helper.cloudinary_url(custom_service_key)

expect(url).to include(conf[:folder])
expect(url).to include(conf[:cloud_name])
end

it 'should respect custom service_name in cl_image_path' do
path = helper.cl_image_path(custom_service_key)

expect(path).to include(conf[:folder])
expect(path).to include(conf[:cloud_name])
end

it 'should respect custom service_name in cl_image_tag' do
tag = helper.cl_image_tag(custom_service_key)

expect(tag).to include(conf[:folder])
expect(tag).to include(conf[:cloud_name])
end
end
6 changes: 0 additions & 6 deletions spec/active_storage/service/configurations.yml

This file was deleted.

4 changes: 2 additions & 2 deletions spec/active_storage/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@

require "yaml"
SERVICE_CONFIGURATIONS = begin
erb = ERB.new(Pathname.new(File.expand_path("service/configurations.yml", __dir__)).read)
erb = ERB.new(Pathname.new(File.expand_path("dummy/config/storage.yml", __dir__)).read)
configuration = YAML.load(erb.result) || {}
configuration.deep_symbolize_keys
rescue Errno::ENOENT
puts "Missing service configuration file in test/service/configurations.yml"
puts "Missing service configuration file in dummy/config/storage.yml"
{}
end

Expand Down

0 comments on commit 4f0b6ac

Please sign in to comment.