activestorage-cloudinary-service 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +44 -0
- data/.ruby-version +1 -0
- data/Gemfile +2 -1
- data/Gemfile.lock +67 -4
- data/README.md +0 -5
- data/activestorage-cloudinary-service.gemspec +2 -2
- data/lib/active_storage/service/cloudinary_service.rb +52 -41
- data/lib/active_storage/service/download_utils.rb +50 -0
- data/lib/active_storage/service/version.rb +1 -1
- metadata +18 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ed3e755146252107a2682fbd64e330be4ad5da2
|
4
|
+
data.tar.gz: dd6ea8202085b611a75cf588c3acd499a632975b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b82f66786e2c685b88b4470a536b8a4d1d97578b61eb0f973a6508b44fb7bce0a406555456a806dc6cbd4791f7ff217f0cbe1a746b5670d323db13f69901c67
|
7
|
+
data.tar.gz: 2fc0f43b8c67469a7b658bf8ec9b9b5d8a5759f29de7b906ddde69fb23f294b4acf35734dabce0e5e71fd80d256ed05ac78eefb8bab7b577413b1f280e9c9ade
|
@@ -0,0 +1,44 @@
|
|
1
|
+
version: 2
|
2
|
+
jobs:
|
3
|
+
build:
|
4
|
+
working_directory: ~/0sc/activestorage-cloudinary-service
|
5
|
+
parallelism: 1
|
6
|
+
shell: /bin/bash --login
|
7
|
+
environment:
|
8
|
+
CIRCLE_ARTIFACTS: /tmp/circleci-artifacts
|
9
|
+
CIRCLE_TEST_REPORTS: /tmp/circleci-test-results
|
10
|
+
docker:
|
11
|
+
- image: circleci/ruby:2.4.2-jessie
|
12
|
+
steps:
|
13
|
+
- checkout
|
14
|
+
- run: mkdir -p $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS
|
15
|
+
- restore_cache:
|
16
|
+
keys:
|
17
|
+
# This branch if available
|
18
|
+
- v1-dep-{{ .Branch }}-
|
19
|
+
# Default branch if not
|
20
|
+
- v1-dep-master-
|
21
|
+
# Any branch if there are none on the default branch - this should be unnecessary if you have your default branch configured correctly
|
22
|
+
- v1-dep-
|
23
|
+
- run: echo -e "export RAILS_ENV=test\nexport RACK_ENV=test" >> $BASH_ENV
|
24
|
+
- run: 'bundle check --path=vendor/bundle || bundle install --path=vendor/bundle
|
25
|
+
--jobs=4 --retry=3'
|
26
|
+
- save_cache:
|
27
|
+
key: v1-dep-{{ .Branch }}-{{ epoch }}
|
28
|
+
paths:
|
29
|
+
# This is a broad list of cache paths to include many possible development environments
|
30
|
+
# You can probably delete some of these entries
|
31
|
+
- vendor/bundle
|
32
|
+
- ~/.bundle
|
33
|
+
- run:
|
34
|
+
command: bundle exec rspec --require spec_helper --format progress spec
|
35
|
+
environment:
|
36
|
+
RAILS_ENV: test
|
37
|
+
RACK_ENV: test
|
38
|
+
- store_test_results:
|
39
|
+
path: /tmp/circleci-test-results
|
40
|
+
# Save artifacts
|
41
|
+
- store_artifacts:
|
42
|
+
path: /tmp/circleci-artifacts
|
43
|
+
- store_artifacts:
|
44
|
+
path: /tmp/circleci-test-results
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.4.2
|
data/Gemfile
CHANGED
@@ -5,4 +5,5 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
|
5
5
|
# Specify your gem's dependencies in active_storage-cloudinary_service.gemspec
|
6
6
|
gemspec
|
7
7
|
|
8
|
-
gem '
|
8
|
+
gem 'activestorage', '~> 5.2.0', require: false
|
9
|
+
gem 'cloudinary', '~> 1.8.2', require: false
|
data/Gemfile.lock
CHANGED
@@ -1,24 +1,82 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
activestorage-cloudinary-service (0.
|
4
|
+
activestorage-cloudinary-service (0.2.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
+
actionpack (5.2.0)
|
10
|
+
actionview (= 5.2.0)
|
11
|
+
activesupport (= 5.2.0)
|
12
|
+
rack (~> 2.0)
|
13
|
+
rack-test (>= 0.6.3)
|
14
|
+
rails-dom-testing (~> 2.0)
|
15
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
16
|
+
actionview (5.2.0)
|
17
|
+
activesupport (= 5.2.0)
|
18
|
+
builder (~> 3.1)
|
19
|
+
erubi (~> 1.4)
|
20
|
+
rails-dom-testing (~> 2.0)
|
21
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
22
|
+
activemodel (5.2.0)
|
23
|
+
activesupport (= 5.2.0)
|
24
|
+
activerecord (5.2.0)
|
25
|
+
activemodel (= 5.2.0)
|
26
|
+
activesupport (= 5.2.0)
|
27
|
+
arel (>= 9.0)
|
28
|
+
activestorage (5.2.0)
|
29
|
+
actionpack (= 5.2.0)
|
30
|
+
activerecord (= 5.2.0)
|
31
|
+
marcel (~> 0.3.1)
|
32
|
+
activesupport (5.2.0)
|
33
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
34
|
+
i18n (>= 0.7, < 2)
|
35
|
+
minitest (~> 5.1)
|
36
|
+
tzinfo (~> 1.1)
|
37
|
+
arel (9.0.0)
|
9
38
|
aws_cf_signer (0.1.3)
|
39
|
+
builder (3.2.3)
|
10
40
|
cloudinary (1.8.2)
|
11
41
|
aws_cf_signer
|
12
42
|
rest-client
|
43
|
+
coderay (1.1.2)
|
44
|
+
concurrent-ruby (1.0.5)
|
45
|
+
crass (1.0.4)
|
13
46
|
diff-lcs (1.3)
|
14
47
|
domain_name (0.5.20170404)
|
15
48
|
unf (>= 0.0.5, < 1.0.0)
|
49
|
+
erubi (1.7.1)
|
16
50
|
http-cookie (1.0.3)
|
17
51
|
domain_name (~> 0.5)
|
52
|
+
i18n (1.0.1)
|
53
|
+
concurrent-ruby (~> 1.0)
|
54
|
+
loofah (2.2.2)
|
55
|
+
crass (~> 1.0.2)
|
56
|
+
nokogiri (>= 1.5.9)
|
57
|
+
marcel (0.3.2)
|
58
|
+
mimemagic (~> 0.3.2)
|
59
|
+
method_source (0.9.0)
|
18
60
|
mime-types (3.1)
|
19
61
|
mime-types-data (~> 3.2015)
|
20
62
|
mime-types-data (3.2016.0521)
|
63
|
+
mimemagic (0.3.2)
|
64
|
+
mini_portile2 (2.3.0)
|
65
|
+
minitest (5.11.3)
|
21
66
|
netrc (0.11.0)
|
67
|
+
nokogiri (1.8.4)
|
68
|
+
mini_portile2 (~> 2.3.0)
|
69
|
+
pry (0.11.3)
|
70
|
+
coderay (~> 1.1.0)
|
71
|
+
method_source (~> 0.9.0)
|
72
|
+
rack (2.0.5)
|
73
|
+
rack-test (1.1.0)
|
74
|
+
rack (>= 1.0, < 3)
|
75
|
+
rails-dom-testing (2.0.3)
|
76
|
+
activesupport (>= 4.2.0)
|
77
|
+
nokogiri (>= 1.6)
|
78
|
+
rails-html-sanitizer (1.0.4)
|
79
|
+
loofah (~> 2.2, >= 2.2.2)
|
22
80
|
rake (10.5.0)
|
23
81
|
rest-client (2.0.2)
|
24
82
|
http-cookie (>= 1.0.2, < 2.0)
|
@@ -37,6 +95,9 @@ GEM
|
|
37
95
|
diff-lcs (>= 1.2.0, < 2.0)
|
38
96
|
rspec-support (~> 3.7.0)
|
39
97
|
rspec-support (3.7.0)
|
98
|
+
thread_safe (0.3.6)
|
99
|
+
tzinfo (1.2.5)
|
100
|
+
thread_safe (~> 0.1)
|
40
101
|
unf (0.1.4)
|
41
102
|
unf_ext
|
42
103
|
unf_ext (0.0.7.4)
|
@@ -45,11 +106,13 @@ PLATFORMS
|
|
45
106
|
ruby
|
46
107
|
|
47
108
|
DEPENDENCIES
|
109
|
+
activestorage (~> 5.2.0)
|
48
110
|
activestorage-cloudinary-service!
|
49
111
|
bundler (~> 1.16)
|
50
|
-
cloudinary
|
112
|
+
cloudinary (~> 1.8.2)
|
113
|
+
pry (~> 0.11.3)
|
51
114
|
rake (~> 10.0)
|
52
|
-
rspec
|
115
|
+
rspec (~> 3.7.0)
|
53
116
|
|
54
117
|
BUNDLED WITH
|
55
|
-
1.16.
|
118
|
+
1.16.2
|
data/README.md
CHANGED
@@ -64,11 +64,6 @@ Currently, active_storage client-side upload doesn't work with Cloudinary. This
|
|
64
64
|
|
65
65
|
Nevertheless, the necessary ground work for this is set and once either active_storage is updated to support more request type or Cloudinary enables support for `PUT` request method, it should work fine.
|
66
66
|
|
67
|
-
## Development
|
68
|
-
|
69
|
-
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
70
|
-
|
71
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
72
67
|
|
73
68
|
## Contributing
|
74
69
|
|
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.require_paths = ['lib']
|
22
22
|
|
23
23
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
24
|
+
spec.add_development_dependency 'pry', '~> 0.11.3'
|
24
25
|
spec.add_development_dependency 'rake', '~> 10.0'
|
25
|
-
spec.add_development_dependency 'rspec'
|
26
|
-
spec.add_development_dependency 'cloudinary'
|
26
|
+
spec.add_development_dependency 'rspec', '~> 3.7.0'
|
27
27
|
end
|
@@ -1,11 +1,15 @@
|
|
1
1
|
require 'cloudinary'
|
2
|
-
|
2
|
+
require_relative 'download_utils'
|
3
3
|
|
4
4
|
module ActiveStorage
|
5
|
+
# Wraps the Cloudinary as an Active Storage service.
|
6
|
+
# See ActiveStorage::Service for the generic API documentation that applies to all services.
|
5
7
|
class Service::CloudinaryService < Service
|
8
|
+
include DownloadUtils
|
9
|
+
|
6
10
|
# FIXME: implement setup for private resource type
|
7
11
|
# FIXME: allow configuration via cloudinary url
|
8
|
-
def initialize(cloud_name:, api_key:, api_secret:, options
|
12
|
+
def initialize(cloud_name:, api_key:, api_secret:, **options)
|
9
13
|
options.merge!(
|
10
14
|
cloud_name: cloud_name,
|
11
15
|
api_key: api_key,
|
@@ -17,28 +21,32 @@ module ActiveStorage
|
|
17
21
|
|
18
22
|
def upload(key, io, checksum: nil)
|
19
23
|
instrument :upload, key: key, checksum: checksum do
|
20
|
-
Cloudinary::Uploader.upload(io, public_id: key)
|
24
|
+
Cloudinary::Uploader.upload(io, public_id: key, resource_type: 'auto')
|
21
25
|
end
|
22
26
|
end
|
23
27
|
|
24
28
|
# Return the content of the file at the +key+.
|
25
|
-
def download(key)
|
26
|
-
tmp_file = open(url_for_public_id(key))
|
29
|
+
def download(key, &block)
|
27
30
|
if block_given?
|
28
31
|
instrument :streaming_download, key: key do
|
29
|
-
|
30
|
-
|
31
|
-
yield data
|
32
|
-
end
|
33
|
-
end
|
32
|
+
source = cloudinary_url_for_key(key)
|
33
|
+
stream_download(source, &block)
|
34
34
|
end
|
35
35
|
else
|
36
36
|
instrument :download, key: key do
|
37
|
-
|
37
|
+
Cloudinary::Downloader.download(key)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
+
# Return the partial content in the byte +range+ of the file at the +key+.
|
43
|
+
def download_chunk(key, range)
|
44
|
+
instrument :download_chunk, key: key, range: range do
|
45
|
+
source = cloudinary_url_for_key(key)
|
46
|
+
download_range(source, range)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
42
50
|
# Delete the file at the +key+.
|
43
51
|
def delete(key)
|
44
52
|
instrument :delete, key: key do
|
@@ -49,9 +57,7 @@ module ActiveStorage
|
|
49
57
|
# Delete files at keys starting with the +prefix+.
|
50
58
|
def delete_prefixed(prefix)
|
51
59
|
instrument :delete_prefixed, prefix: prefix do
|
52
|
-
|
53
|
-
delete_resource_with_public_id(resource['public_id'])
|
54
|
-
end
|
60
|
+
Cloudinary::Api.delete_resources_by_prefix(prefix)
|
55
61
|
end
|
56
62
|
end
|
57
63
|
|
@@ -87,9 +93,15 @@ module ActiveStorage
|
|
87
93
|
expires_in: expires_in,
|
88
94
|
content_type: content_type,
|
89
95
|
content_length: content_length,
|
90
|
-
checksum: checksum
|
96
|
+
checksum: checksum,
|
97
|
+
resource_type: 'auto'
|
91
98
|
}
|
92
|
-
|
99
|
+
|
100
|
+
# FIXME: Cloudinary Ruby SDK does't expose an api for signed upload url
|
101
|
+
# The expected url is similar to the private_download_url
|
102
|
+
# with download replaced with upload
|
103
|
+
signed_download_url_for_public_id(key, options)
|
104
|
+
.sub(/download/, 'upload')
|
93
105
|
end
|
94
106
|
end
|
95
107
|
|
@@ -108,49 +120,48 @@ module ActiveStorage
|
|
108
120
|
Cloudinary::Api.resources_by_ids(public_id).fetch('resources')
|
109
121
|
end
|
110
122
|
|
111
|
-
def find_resources_with_public_id_prefix(prefix)
|
112
|
-
Cloudinary::Api.resources(type: :upload, prefix: prefix).fetch('resources')
|
113
|
-
end
|
114
|
-
|
115
123
|
def delete_resource_with_public_id(public_id)
|
116
124
|
Cloudinary::Uploader.destroy(public_id)
|
117
125
|
end
|
118
126
|
|
119
|
-
def url_for_public_id(public_id)
|
120
|
-
Cloudinary::Api.resource(public_id)['secure_url']
|
121
|
-
end
|
122
|
-
|
123
|
-
# FIXME: Cloudinary Ruby SDK does't expose an api for signed upload url
|
124
|
-
# The expected url is similar to the private_download_url
|
125
|
-
# with download replaced with upload
|
126
|
-
def direct_upload_url_for_public_id(public_id, options)
|
127
|
-
# allow the server to auto detect the resource_type
|
128
|
-
options[:resource_type] ||= 'auto'
|
129
|
-
signed_download_url_for_public_id(public_id, options).sub(/download/, 'upload')
|
130
|
-
end
|
131
|
-
|
132
127
|
def signed_download_url_for_public_id(public_id, options)
|
133
|
-
|
128
|
+
extension = resource_format(options[:filename])
|
129
|
+
options[:resource_type] ||= resource_type(extension)
|
130
|
+
|
134
131
|
Cloudinary::Utils.private_download_url(
|
135
|
-
public_id,
|
136
|
-
|
132
|
+
finalize_public_id(public_id, extension, options[:resource_type]),
|
133
|
+
extension,
|
137
134
|
signed_url_options(options)
|
138
135
|
)
|
139
136
|
end
|
140
137
|
|
138
|
+
# TODO: for assets of type raw,
|
139
|
+
# cloudinary request the extension to be part of the public_id
|
140
|
+
def finalize_public_id(public_id, extension, resource_type)
|
141
|
+
return public_id unless resource_type == 'raw'
|
142
|
+
public_id + '.' + extension
|
143
|
+
end
|
144
|
+
|
141
145
|
def signed_url_options(options)
|
142
146
|
{
|
143
|
-
resource_type: (options[:resource_type] || '
|
147
|
+
resource_type: (options[:resource_type] || 'image'),
|
144
148
|
type: (options[:type] || 'upload'),
|
145
|
-
attachment: (options[:
|
149
|
+
attachment: (options[:disposition]&.to_sym == :attachment),
|
146
150
|
expires_at: (Time.now + options[:expires_in])
|
147
151
|
}
|
148
152
|
end
|
149
153
|
|
150
|
-
def resource_format(
|
154
|
+
def resource_format(filename)
|
155
|
+
extension = filename&.extension_with_delimiter || ''
|
156
|
+
extension.sub('.', '')
|
157
|
+
end
|
158
|
+
|
159
|
+
def resource_type(extension)
|
160
|
+
Cloudinary::Utils.resource_type_for_format(extension)
|
161
|
+
end
|
151
162
|
|
152
|
-
def
|
153
|
-
|
163
|
+
def cloudinary_url_for_key(key)
|
164
|
+
Cloudinary::Utils.cloudinary_url(key)
|
154
165
|
end
|
155
166
|
end
|
156
167
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'openssl'
|
3
|
+
|
4
|
+
module DownloadUtils
|
5
|
+
def stream_download(source, chunk_size = 5_242_880)
|
6
|
+
url = URI.parse(source)
|
7
|
+
http, req = setup_connection(url)
|
8
|
+
|
9
|
+
content_length = http.request_head(url).content_length
|
10
|
+
upper_limit = content_length + (content_length % chunk_size)
|
11
|
+
offset = 0
|
12
|
+
|
13
|
+
http.start do |agent|
|
14
|
+
while offset < upper_limit
|
15
|
+
lim = (offset + chunk_size)
|
16
|
+
# QUESTION: is it relevant to set the last chunk
|
17
|
+
# to the exact remaining bytes
|
18
|
+
# lim = content_length if lim > content_length
|
19
|
+
req.range = (offset..lim)
|
20
|
+
|
21
|
+
chunk = agent.request(req).body
|
22
|
+
yield chunk.force_encoding(Encoding::BINARY)
|
23
|
+
|
24
|
+
offset += chunk_size + 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def download_range(source, range)
|
30
|
+
url = URI.parse(source)
|
31
|
+
http, req = setup_connection(url)
|
32
|
+
req.range = range
|
33
|
+
|
34
|
+
chunk = http.start { |agent| agent.request(req).body }
|
35
|
+
chunk.force_encoding(Encoding::BINARY)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def setup_connection(url)
|
41
|
+
http = Net::HTTP.new(url.host, url.port)
|
42
|
+
req = Net::HTTP::Get.new(url.request_uri)
|
43
|
+
|
44
|
+
if url.port == 443
|
45
|
+
http.use_ssl = true
|
46
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
47
|
+
end
|
48
|
+
[http, req]
|
49
|
+
end
|
50
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activestorage-cloudinary-service
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Osmond Oscar
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-07-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -25,47 +25,47 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.16'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: pry
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 0.11.3
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 0.11.3
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
47
|
+
version: '10.0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
54
|
+
version: '10.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 3.7.0
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: 3.7.0
|
69
69
|
description:
|
70
70
|
email:
|
71
71
|
- oskarromero3@gmail.com
|
@@ -73,8 +73,10 @@ executables: []
|
|
73
73
|
extensions: []
|
74
74
|
extra_rdoc_files: []
|
75
75
|
files:
|
76
|
+
- ".circleci/config.yml"
|
76
77
|
- ".gitignore"
|
77
78
|
- ".rspec"
|
79
|
+
- ".ruby-version"
|
78
80
|
- CODE_OF_CONDUCT.md
|
79
81
|
- Gemfile
|
80
82
|
- Gemfile.lock
|
@@ -85,6 +87,7 @@ files:
|
|
85
87
|
- bin/console
|
86
88
|
- bin/setup
|
87
89
|
- lib/active_storage/service/cloudinary_service.rb
|
90
|
+
- lib/active_storage/service/download_utils.rb
|
88
91
|
- lib/active_storage/service/version.rb
|
89
92
|
homepage: https://github.com/0sc/activestorage-cloudinary-service
|
90
93
|
licenses:
|