cloudinary 1.9.1 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +5 -5
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +42 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +21 -0
  4. data/.github/pull_request_template.md +24 -0
  5. data/.gitignore +7 -1
  6. data/.travis.yml +15 -8
  7. data/CHANGELOG.md +261 -0
  8. data/README.md +3 -0
  9. data/Rakefile +3 -45
  10. data/cloudinary.gemspec +27 -20
  11. data/lib/active_storage/blob_key.rb +20 -0
  12. data/lib/active_storage/service/cloudinary_service.rb +249 -0
  13. data/lib/cloudinary.rb +53 -63
  14. data/lib/cloudinary/account_api.rb +231 -0
  15. data/lib/cloudinary/account_config.rb +30 -0
  16. data/lib/cloudinary/api.rb +228 -71
  17. data/lib/cloudinary/auth_token.rb +10 -4
  18. data/lib/cloudinary/base_api.rb +79 -0
  19. data/lib/cloudinary/base_config.rb +70 -0
  20. data/lib/cloudinary/cache.rb +38 -0
  21. data/lib/cloudinary/cache/breakpoints_cache.rb +31 -0
  22. data/lib/cloudinary/cache/key_value_cache_adapter.rb +25 -0
  23. data/lib/cloudinary/cache/rails_cache_adapter.rb +34 -0
  24. data/lib/cloudinary/cache/storage/rails_cache_storage.rb +5 -0
  25. data/lib/cloudinary/carrier_wave.rb +4 -2
  26. data/lib/cloudinary/carrier_wave/remote.rb +3 -2
  27. data/lib/cloudinary/carrier_wave/storage.rb +2 -1
  28. data/lib/cloudinary/{controller.rb → cloudinary_controller.rb} +3 -5
  29. data/lib/cloudinary/config.rb +43 -0
  30. data/lib/cloudinary/helper.rb +77 -7
  31. data/lib/cloudinary/migrator.rb +3 -1
  32. data/lib/cloudinary/railtie.rb +7 -3
  33. data/lib/cloudinary/responsive.rb +111 -0
  34. data/lib/cloudinary/uploader.rb +67 -15
  35. data/lib/cloudinary/utils.rb +324 -54
  36. data/lib/cloudinary/version.rb +1 -1
  37. data/lib/cloudinary/video_helper.rb +96 -22
  38. data/lib/tasks/cloudinary/fetch_assets.rake +48 -0
  39. data/lib/tasks/{cloudinary.rake → cloudinary/sync_static.rake} +0 -0
  40. data/tools/allocate_test_cloud.sh +9 -0
  41. data/tools/get_test_cloud.sh +9 -0
  42. data/tools/update_version +220 -0
  43. data/vendor/assets/javascripts/cloudinary/jquery.cloudinary.js +51 -13
  44. data/vendor/assets/javascripts/cloudinary/jquery.fileupload.js +24 -4
  45. data/vendor/assets/javascripts/cloudinary/jquery.ui.widget.js +741 -561
  46. data/vendor/assets/javascripts/cloudinary/load-image.all.min.js +1 -1
  47. metadata +92 -67
  48. data/spec/access_control_spec.rb +0 -99
  49. data/spec/api_spec.rb +0 -545
  50. data/spec/archive_spec.rb +0 -129
  51. data/spec/auth_token_spec.rb +0 -79
  52. data/spec/cloudinary_helper_spec.rb +0 -190
  53. data/spec/cloudinary_spec.rb +0 -32
  54. data/spec/data/sync_static/app/assets/javascripts/1.coffee +0 -1
  55. data/spec/data/sync_static/app/assets/javascripts/1.js +0 -1
  56. data/spec/data/sync_static/app/assets/stylesheets/1.css +0 -3
  57. data/spec/docx.docx +0 -0
  58. data/spec/favicon.ico +0 -0
  59. data/spec/logo.png +0 -0
  60. data/spec/rake_spec.rb +0 -160
  61. data/spec/sample_asset_file.tsv +0 -4
  62. data/spec/search_spec.rb +0 -109
  63. data/spec/spec_helper.rb +0 -245
  64. data/spec/storage_spec.rb +0 -44
  65. data/spec/streaminig_profiles_api_spec.rb +0 -74
  66. data/spec/support/helpers/temp_file_helpers.rb +0 -22
  67. data/spec/support/shared_contexts/rake.rb +0 -19
  68. data/spec/uploader_spec.rb +0 -363
  69. data/spec/utils_methods_spec.rb +0 -54
  70. data/spec/utils_spec.rb +0 -906
  71. data/spec/video_tag_spec.rb +0 -251
  72. data/spec/video_url_spec.rb +0 -164
data/cloudinary.gemspec CHANGED
@@ -15,33 +15,40 @@ Gem::Specification.new do |s|
15
15
 
16
16
  s.rubyforge_project = "cloudinary"
17
17
 
18
- s.files = (`git ls-files`.split("\n") - `git ls-files samples`.split("\n")) + Dir.glob("vendor/assets/javascripts/*/*") + Dir.glob("vendor/assets/html/*")
19
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.files = `git ls-files`.split("\n").select { |f| !f.start_with?("test", "spec", "features", "samples") } + Dir.glob("vendor/assets/javascripts/*/*") + Dir.glob("vendor/assets/html/*")
20
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
20
  s.require_paths = ["lib"]
22
21
 
23
22
  s.add_dependency "aws_cf_signer"
24
- s.add_development_dependency "rspec", '>=3.5'
25
- s.add_development_dependency "rspec-rails"
26
- s.add_development_dependency "rake"
27
23
 
28
- if RUBY_VERSION > "2.0"
24
+ if RUBY_VERSION >= "2.0.0"
25
+ s.add_dependency "rest-client", ">= 2.0.0"
26
+ else
29
27
  s.add_dependency "rest-client"
30
- s.add_development_dependency "actionpack"
31
- s.add_development_dependency "simplecov"
32
- s.add_development_dependency "rubyzip"
33
- elsif RUBY_VERSION >= "1.9"
34
- s.add_dependency "rest-client", '< 2.0'
35
- s.add_dependency 'json', '~> 1.8'
36
- s.add_development_dependency "actionpack", '< 5.0'
37
- s.add_development_dependency "simplecov"
38
- s.add_development_dependency "nokogiri", "<1.7.0"
39
- s.add_development_dependency "rubyzip", '<1.2.1'
28
+ end
29
+
30
+ s.add_development_dependency "actionpack"
31
+ s.add_development_dependency "nokogiri"
32
+
33
+ if RUBY_VERSION >= "2.2.0"
34
+ s.add_development_dependency "rake", ">= 13.0.1"
40
35
  else
41
- s.add_dependency "i18n", "<0.7.0"
42
- s.add_dependency "rest-client", "<=1.6.8"
43
- s.add_development_dependency "actionpack", "~>3.2.0"
44
- s.add_development_dependency "nokogiri", "<1.6.0"
36
+ s.add_development_dependency "rake", "<= 12.2.1"
45
37
  end
46
38
 
39
+ s.add_development_dependency "sqlite3"
40
+ s.add_development_dependency "rspec", '>=3.5'
41
+ s.add_development_dependency "rspec-retry"
42
+ s.add_development_dependency "rails", "~>5.2" if RUBY_VERSION >= "2.2.2"
43
+
44
+ s.add_development_dependency "railties", "<= 4.2.7" if RUBY_VERSION <= "1.9.3"
45
+ s.add_development_dependency "rspec-rails"
46
+
47
+ s.add_development_dependency "rubyzip"
48
+
49
+ if RUBY_VERSION <= "2.4.0"
50
+ s.add_development_dependency "simplecov", "<= 0.17.1" # support testing Ruby 1.9
51
+ else
52
+ s.add_development_dependency "simplecov", "> 0.18.0"
53
+ end
47
54
  end
@@ -0,0 +1,20 @@
1
+ # Allow Blob attributes to be passed down to the service
2
+ # attributes includes
3
+ # - key - the string the BlobKey represents
4
+ # - content_type
5
+ # - filename
6
+ module ActiveStorage
7
+ class BlobKey < String
8
+ attr_reader :attributes
9
+ def initialize(attributes)
10
+ if attributes.is_a? Hash
11
+ attributes.symbolize_keys!
12
+ super(attributes[:key])
13
+ @attributes = attributes
14
+ else
15
+ super(attributes)
16
+ @attributes = {key: attributes} if attributes
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,249 @@
1
+ require 'active_storage/blob_key'
2
+ require 'cloudinary/helper'
3
+ require 'net/http'
4
+
5
+ unless ActiveStorage::Blob.method_defined? :original_key
6
+ class ActiveStorage::Blob
7
+ alias_method :original_key, :key
8
+
9
+ def key
10
+ original_key
11
+ ActiveStorage::BlobKey.new(@attributes.as_json)
12
+ end
13
+ end
14
+ end
15
+
16
+ module CloudinaryHelper
17
+ alias cloudinary_url_internal_original cloudinary_url_internal
18
+
19
+ def cloudinary_url_internal(source, options = {})
20
+ source = ActiveStorage::Blob.service.public_id(source) if defined? ActiveStorage::Blob.service.public_id
21
+ cloudinary_url_internal_original(source, options)
22
+ end
23
+ end
24
+
25
+ module ActiveStorage
26
+ class Service::CloudinaryService < Service
27
+ module Headers
28
+ CONTENT_TYPE = "Content-Type".freeze
29
+ CONTENT_MD5 = "Content-MD5".freeze
30
+ end
31
+ attr_reader :upload_options
32
+
33
+ def initialize(**options)
34
+ @options = options
35
+ end
36
+
37
+ def upload(key, io, filename: nil, checksum: nil, **options)
38
+ instrument :upload, key: key, checksum: checksum do
39
+ begin
40
+ extra_headers = checksum.nil? ? {} : {Headers::CONTENT_MD5 => checksum}
41
+ options = @options.merge(options)
42
+ Cloudinary::Uploader.upload(
43
+ io,
44
+ public_id: public_id_internal(key),
45
+ resource_type: resource_type(io, key),
46
+ context: {active_storage_key: key, checksum: checksum},
47
+ extra_headers: extra_headers,
48
+ **options
49
+ )
50
+ rescue CloudinaryException => e
51
+ raise ActiveStorage::IntegrityError, e.message, e.backtrace
52
+ end
53
+ end
54
+ end
55
+
56
+ def url(key, filename: nil, content_type: '', **options)
57
+ instrument :url, key: key do |payload|
58
+ url = Cloudinary::Utils.cloudinary_url(
59
+ public_id(key),
60
+ resource_type: resource_type(nil, key),
61
+ format: ext_for_file(key, filename, content_type),
62
+ **@options.merge(options.symbolize_keys)
63
+ )
64
+
65
+ payload[:url] = url
66
+
67
+ url
68
+ end
69
+ end
70
+
71
+ def url_for_direct_upload(key, **options)
72
+ instrument :url, key: key do |payload|
73
+ options = {:resource_type => resource_type(nil, key)}.merge(@options.merge(options.symbolize_keys))
74
+ options[:public_id] = public_id_internal(key)
75
+ # Provide file format for raw files, since js client does not include original file name.
76
+ #
77
+ # When the file is uploaded from the server, the request includes original filename. That allows Cloudinary
78
+ # to identify file extension and append it to the public id of the file (raw files include file extension
79
+ # in their public id, opposed to transformable assets (images/video) that use only basename). When uploading
80
+ # through direct upload (client side js), filename is missing, and that leads to inconsistent/broken URLs.
81
+ # To avoid that, we explicitly pass file format in options.
82
+ options[:format] = ext_for_file(key) if options[:resource_type] == "raw"
83
+ options[:context] = {active_storage_key: key}
84
+ options.delete(:file)
85
+ payload[:url] = api_uri("upload", options)
86
+ end
87
+ end
88
+
89
+ def headers_for_direct_upload(key, content_type:, checksum:, **)
90
+ {
91
+ Headers::CONTENT_TYPE => content_type,
92
+ Headers::CONTENT_MD5 => checksum,
93
+ }
94
+ end
95
+
96
+ def delete(key)
97
+ instrument :delete, key: key do
98
+ options = {
99
+ resource_type: resource_type(nil, key),
100
+ type: @options[:type]
101
+ }.compact
102
+
103
+ Cloudinary::Uploader.destroy public_id(key), **options
104
+ end
105
+ end
106
+
107
+ def delete_prefixed(prefix)
108
+ # This method is used by ActiveStorage to delete derived resources after the main resource was deleted.
109
+ # In Cloudinary, the derived resources are deleted automatically when the main resource is deleted.
110
+ end
111
+
112
+ def exist?(key)
113
+ instrument :exist, key: key do |payload|
114
+ begin
115
+ options = {
116
+ resource_type: resource_type(nil, key),
117
+ type: @options[:type]
118
+ }.compact
119
+
120
+ Cloudinary::Api.resource public_id(key), **options
121
+ true
122
+ rescue Cloudinary::Api::NotFound => e
123
+ false
124
+ end
125
+ end
126
+ end
127
+
128
+ def download(key, &block)
129
+ uri = URI(url(key))
130
+ if block_given?
131
+ instrument :streaming_download, key: key do
132
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
133
+ request = Net::HTTP::Get.new uri
134
+ http.request request do |response|
135
+ response.read_body &block
136
+ end
137
+ end
138
+ end
139
+ else
140
+ instrument :download, key: key do
141
+ res = Net::HTTP::get_response(uri)
142
+ res.body
143
+ end
144
+ end
145
+ end
146
+
147
+ # Return the partial content in the byte +range+ of the file at the +key+.
148
+ def download_chunk(key, range)
149
+ url = Cloudinary::Utils.unsigned_download_url(public_id(key), resource_type: resource_type(nil, key))
150
+ uri = URI(url)
151
+ instrument :download, key: key do
152
+ req = Net::HTTP::Get.new(uri)
153
+ range_end = case
154
+ when range.end.nil? then ''
155
+ when range.exclude_end? then range.end - 1
156
+ else range.end
157
+ end
158
+ req['range'] = "bytes=#{[range.begin, range_end].join('-')}"
159
+ res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
160
+ http.request(req)
161
+ end
162
+ res.body.force_encoding(Encoding::BINARY)
163
+ end
164
+
165
+ end
166
+
167
+ def public_id(key)
168
+ return key unless @options[:folder]
169
+
170
+ File.join(@options.fetch(:folder), public_id_internal(key))
171
+ end
172
+
173
+ private
174
+
175
+ def api_uri(action, options)
176
+ base_url = Cloudinary::Utils.cloudinary_api_url(action, options)
177
+ upload_params = Cloudinary::Uploader.build_upload_params(options)
178
+
179
+ upload_params.reject! { |k, v| Cloudinary::Utils.safe_blank?(v) }
180
+ unless options[:unsigned]
181
+ upload_params = Cloudinary::Utils.sign_request(upload_params, options)
182
+ end
183
+ "#{base_url}?#{upload_params.to_query}"
184
+ end
185
+
186
+ # Helper method for getting the filename extension.
187
+ #
188
+ # It does the best effort when original filename does not include extension, but we know the mime-type.
189
+ #
190
+ # @param [ActiveStorage::BlobKey] key The blob key with attributes.
191
+ # @param [ActiveStorage::Filename] filename The original filename.
192
+ # @param [string] content_type The content type of the file.
193
+ #
194
+ # @return [string] The extension of the filename.
195
+ def ext_for_file(key, filename = nil, content_type = nil)
196
+ if filename.blank?
197
+ options = key.respond_to?(:attributes) ? key.attributes : {}
198
+ filename = ActiveStorage::Filename.new(options[:filename]) if options.has_key?(:filename)
199
+ end
200
+ ext = filename.respond_to?(:extension_without_delimiter) ? filename.extension_without_delimiter : nil
201
+
202
+ return ext unless ext.blank?
203
+
204
+ # Raw files are not convertible, no extension guessing for them
205
+ return nil if content_type_to_resource_type(content_type).eql?('raw')
206
+
207
+ # Fallback when there is no extension.
208
+ @formats ||= Hash.new do |h, key|
209
+ ext = Rack::Mime::MIME_TYPES.invert[key]
210
+ h[key] = ext.slice(1..-1) unless ext.nil?
211
+ end
212
+ @formats[content_type]
213
+ end
214
+
215
+ def public_id_internal(key)
216
+ # TODO: Allow custom manipulation of key to obscure how we store in Cloudinary
217
+ key
218
+ end
219
+
220
+ def content_type_to_resource_type(content_type)
221
+ return 'image' if content_type.nil?
222
+
223
+ type, subtype = content_type.split('/')
224
+ case type
225
+ when 'video', 'audio'
226
+ 'video'
227
+ when 'text'
228
+ 'raw'
229
+ when 'application'
230
+ case subtype
231
+ when 'pdf', 'postscript'
232
+ 'image'
233
+ when 'vnd.apple.mpegurl', 'x-mpegurl', 'mpegurl' # m3u8
234
+ 'video'
235
+ else
236
+ 'raw'
237
+ end
238
+ else
239
+ 'image'
240
+ end
241
+ end
242
+
243
+ def resource_type(io, key = "")
244
+ options = key.respond_to?(:attributes) ? key.attributes : {}
245
+ content_type = options[:content_type] || (io.nil? ? '' : Marcel::MimeType.for(io))
246
+ content_type_to_resource_type(content_type)
247
+ end
248
+ end
249
+ end
data/lib/cloudinary.rb CHANGED
@@ -16,7 +16,12 @@ require "cloudinary/missing"
16
16
  module Cloudinary
17
17
  autoload :Utils, 'cloudinary/utils'
18
18
  autoload :Uploader, 'cloudinary/uploader'
19
+ autoload :BaseConfig, "cloudinary/base_config"
20
+ autoload :Config, "cloudinary/config"
21
+ autoload :AccountConfig, "cloudinary/account_config"
22
+ autoload :BaseApi, "cloudinary/base_api"
19
23
  autoload :Api, "cloudinary/api"
24
+ autoload :AccountApi, "cloudinary/account_api"
20
25
  autoload :Downloader, "cloudinary/downloader"
21
26
  autoload :Blob, "cloudinary/blob"
22
27
  autoload :PreloadedFile, "cloudinary/preloaded_file"
@@ -29,8 +34,8 @@ module Cloudinary
29
34
  OLD_AKAMAI_SHARED_CDN = "cloudinary-a.akamaihd.net"
30
35
  SHARED_CDN = AKAMAI_SHARED_CDN
31
36
 
32
- USER_AGENT = "CloudinaryRuby/" + VERSION
33
- @@user_platform = ""
37
+ USER_AGENT = "CloudinaryRuby/#{VERSION} (Ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL})"
38
+ @@user_platform = defined?(Rails.version) ? "Rails/#{Rails.version}" : ""
34
39
 
35
40
  # Add platform information to the USER_AGENT header
36
41
  # This is intended for platform information and not individual applications!
@@ -44,7 +49,7 @@ module Cloudinary
44
49
 
45
50
  def self.USER_AGENT
46
51
  if @@user_platform.empty?
47
- "#{USER_AGENT}"
52
+ USER_AGENT
48
53
  else
49
54
  "#{@@user_platform} #{USER_AGENT}"
50
55
  end
@@ -58,71 +63,42 @@ module Cloudinary
58
63
  "ept" => "eps"
59
64
  }
60
65
 
61
- @@config = nil
62
-
66
+ # Cloudinary config
67
+ #
68
+ # @param [Hash] new_config If +new_config+ is passed, Config will be updated with it
69
+ # @yieldparam [OpenStruct] Config can be updated in the block
70
+ #
71
+ # @return [OpenStruct]
63
72
  def self.config(new_config=nil)
64
- first_time = @@config.nil?
65
- @@config ||= OpenStruct.new((YAML.load(ERB.new(IO.read(config_dir.join("cloudinary.yml"))).result)[config_env] rescue {}))
66
-
67
- # Heroku support
68
- if first_time && ENV["CLOUDINARY_CLOUD_NAME"]
69
- set_config(
70
- "cloud_name" => ENV["CLOUDINARY_CLOUD_NAME"],
71
- "api_key" => ENV["CLOUDINARY_API_KEY"],
72
- "api_secret" => ENV["CLOUDINARY_API_SECRET"],
73
- "secure_distribution" => ENV["CLOUDINARY_SECURE_DISTRIBUTION"],
74
- "private_cdn" => ENV["CLOUDINARY_PRIVATE_CDN"].to_s == 'true',
75
- "secure" => ENV["CLOUDINARY_SECURE"].to_s == 'true'
76
- )
77
- elsif first_time && ENV["CLOUDINARY_URL"]
78
- config_from_url(ENV["CLOUDINARY_URL"])
79
- end
73
+ @@config ||= make_new_config(Config)
80
74
 
81
- set_config(new_config) if new_config
82
- yield(@@config) if block_given?
75
+ @@config.update(new_config) if new_config
76
+ yield @@config if block_given?
83
77
 
84
78
  @@config
85
79
  end
86
80
 
87
- def self.config_from_url(url)
88
- @@config ||= OpenStruct.new
89
- uri = URI.parse(url)
90
- set_config(
91
- "cloud_name" => uri.host,
92
- "api_key" => uri.user,
93
- "api_secret" => uri.password,
94
- "private_cdn" => !uri.path.blank?,
95
- "secure_distribution" => uri.path[1..-1]
96
- )
97
- uri.query.to_s.split("&").each do
98
- |param|
99
- key, value = param.split("=")
100
- if isNestedKey? key
101
- putNestedKey key, value
102
- else
103
- set_config(key => URI.decode(value))
104
- end
105
- end
106
- end
81
+ # Cloudinary account config
82
+ #
83
+ # @param [Hash] new_config If +new_config+ is passed, Account Config will be updated with it
84
+ # @yieldparam [OpenStruct] Account config can be updated in the block
85
+ #
86
+ # @return [OpenStruct]
87
+ def self.account_config(new_config=nil)
88
+ @@account_config ||= make_new_config(AccountConfig)
107
89
 
108
- def self.putNestedKey(key, value)
109
- chain = key.split(/[\[\]]+/).reject { |i| i.empty? }
110
- outer = @@config
111
- lastKey = chain.pop()
112
- chain.each do |innerKey|
113
- inner = outer[innerKey]
114
- if inner.nil?
115
- inner = OpenStruct.new
116
- outer[innerKey] = inner
117
- end
118
- outer = inner
119
- end
120
- outer[lastKey] = value
90
+ @@account_config.update(new_config) if new_config
91
+ yield @@account_config if block_given?
92
+
93
+ @@account_config
121
94
  end
122
95
 
96
+ def self.config_from_url(url)
97
+ config.load_from_url(url)
98
+ end
123
99
 
124
- def self.isNestedKey?(key)
125
- /\w+\[\w+\]/ =~ key
100
+ def self.config_from_account_url(url)
101
+ account_config.load_from_url(url)
126
102
  end
127
103
 
128
104
  def self.app_root
@@ -135,25 +111,39 @@ module Cloudinary
135
111
  end
136
112
 
137
113
  private
138
-
114
+
139
115
  def self.config_env
140
116
  return ENV["CLOUDINARY_ENV"] if ENV["CLOUDINARY_ENV"]
141
117
  return Rails.env if defined? Rails::env
142
118
  nil
143
119
  end
144
-
120
+
145
121
  def self.config_dir
146
- return Pathname.new(ENV["CLOUDINARY_CONFIG_DIR"]) if ENV["CLOUDINARY_CONFIG_DIR"]
122
+ return Pathname.new(ENV["CLOUDINARY_CONFIG_DIR"]) if ENV["CLOUDINARY_CONFIG_DIR"]
147
123
  self.app_root.join("config")
148
124
  end
149
-
125
+
150
126
  def self.set_config(new_config)
151
127
  new_config.each{|k,v| @@config.send(:"#{k}=", v) if !v.nil?}
152
128
  end
129
+
130
+ # Builds config from yaml file, extends it with specific module and loads configuration from environment variable
131
+ #
132
+ # @param [Module] config_module Config is extended with this module after being built
133
+ #
134
+ # @return [OpenStruct]
135
+ def self.make_new_config(config_module)
136
+ OpenStruct.new((YAML.load(ERB.new(IO.read(config_dir.join("cloudinary.yml"))).result)[config_env] rescue {})).tap do |config|
137
+ config.extend(config_module)
138
+ config.load_config_from_env
139
+ end
140
+ end
141
+
142
+ private_class_method :make_new_config
153
143
  end
154
144
  # Prevent require loop if included after Rails is already initialized.
155
145
  require "cloudinary/helper" if defined?(::ActionView::Base)
156
- require "cloudinary/controller" if defined?(::ActionController::Base)
146
+ require "cloudinary/cloudinary_controller" if defined?(::ActionController::Base)
157
147
  require "cloudinary/railtie" if defined?(Rails) && defined?(Rails::Railtie)
158
148
  require "cloudinary/engine" if defined?(Rails) && defined?(Rails::Engine)
159
149