Module: Cloudinary::CarrierWave

Defined in:
lib/cloudinary/carrier_wave/preloaded.rb,
lib/cloudinary/carrier_wave.rb,
lib/cloudinary/carrier_wave/error.rb,
lib/cloudinary/carrier_wave/remote.rb,
lib/cloudinary/carrier_wave/process.rb
more...

Overview

Copyright Cloudinary Support for store in CarrierWave files that were preloaded to cloudinary (e.g., by javascript) Field value must be in the format: “image/upload/v<version>/<public_id>.<format>#<signature>” Where signature is the cloudinary API signature on the public_id and version.

Defined Under Namespace

Modules: ClassMethods Classes: CloudinaryFile, PreloadedCloudinaryFile, RemoteFile, Storage, StoredFile, UploadError

Constant Summary collapse

SANITIZE_REGEXP =
CarrierWave::SanitizedFile.respond_to?(:sanitize_regexp) ? CarrierWave::SanitizedFile.sanitize_regexp : /[^a-zA-Z0-9\.\-\+_]/
PRELOADED_CLOUDINARY_PATH =
Cloudinary::PreloadedFile::PRELOADED_CLOUDINARY_PATH
STORED_CLOUDINARY_PATH =
/^([^\/]+)\/([^\/]+)\/v(\d+)\/([^#]+)$/
SHORT_STORED_CLOUDINARY_PATH =
/^v(\d+)\/([^#]+)$/

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.createRawOrPreloaded(file) ⇒ Object

[View source]

88
89
90
91
92
# File 'lib/cloudinary/carrier_wave/preloaded.rb', line 88

def self.createRawOrPreloaded(file)
  return file if file.is_a?(Cloudinary::CarrierWave::StoredFile)
  return PreloadedCloudinaryFile.new(file) if file.is_a?(String) && file.match(PRELOADED_CLOUDINARY_PATH)
  nil
end

.included(base) ⇒ Object

[View source]

10
11
12
13
14
15
16
17
# File 'lib/cloudinary/carrier_wave.rb', line 10

def self.included(base)
  base.storage Cloudinary::CarrierWave::Storage
  base.cache_storage = :file if base.cache_storage.blank?
  base.extend ClassMethods
  base.class_attribute :metadata
  base.class_attribute :storage_type, instance_reader: false
  override_in_versions(base, :blank?, :full_public_id, :my_public_id, :all_versions_processors, :stored_version)
end

.override_in_versions(base, *methods) ⇒ Object

For the given methods - versions should call the main uploader method

[View source]

208
209
210
211
212
213
214
215
216
217
# File 'lib/cloudinary/carrier_wave.rb', line 208

def self.override_in_versions(base, *methods)
  methods.each do
    |method|
    base.send :define_method, method do
      return super() if self.version_name.blank?
      uploader = self.model.send(self.mounted_as)
      uploader.send(method)
    end
  end
end

Instance Method Details

#all_processorsObject

[View source]

124
125
126
# File 'lib/cloudinary/carrier_wave/process.rb', line 124

def all_processors
  (self.is_main_uploader? ? [] : all_versions_processors) + self.class.processors
end

#all_versions_processorsObject

[View source]

118
119
120
121
122
# File 'lib/cloudinary/carrier_wave/process.rb', line 118

def all_versions_processors
  all_versions = self.class.instance_variable_get('@all_versions')

  all_versions ? all_versions.processors : []
end

#auto_rename_preloaded?Boolean

Rename preloaded uploads if public_id was overridden

Returns:

  • (Boolean)
[View source]

141
142
143
# File 'lib/cloudinary/carrier_wave.rb', line 141

def auto_rename_preloaded?
  true
end

#cache!(new_file) ⇒ Object

[View source]

10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/cloudinary/carrier_wave/preloaded.rb', line 10

def cache!(new_file)
  file = Cloudinary::CarrierWave::createRawOrPreloaded(new_file)
  if file
    @file = file
    @stored_version = @file.version
    @public_id = @stored_public_id = @file.public_id
    self.original_filename = sanitize(@file.original_filename)
    @cache_id = "unused" # must not be blank 
  else
    super
    @public_id = nil # allow overriding public_id
  end
end

#cache_nameObject

[View source]

38
39
40
# File 'lib/cloudinary/carrier_wave/preloaded.rb', line 38

def cache_name
  return (@file.is_a?(PreloadedCloudinaryFile) || @file.is_a?(StoredFile)) ? @file.to_s : super
end

#cache_versions!(new_file = nil) ⇒ Object

[View source]

116
117
118
# File 'lib/cloudinary/carrier_wave.rb', line 116

def cache_versions!(new_file=nil)
  # Do nothing
end

#cloudinary_should_handle_remote?Boolean

Let Cloudinary download remote URLs directly

Returns:

  • (Boolean)
[View source]

136
137
138
# File 'lib/cloudinary/carrier_wave.rb', line 136

def cloudinary_should_handle_remote?
  true
end

#default_formatObject

[View source]

195
196
197
# File 'lib/cloudinary/carrier_wave.rb', line 195

def default_format
  "png"
end

#default_public_idObject

default public_id to use if no uploaded file. Override with public_id of an uploaded image if you want a default image.

[View source]

73
74
75
# File 'lib/cloudinary/carrier_wave.rb', line 73

def default_public_id
  nil
end

#delete_remote?Boolean

Should removed files be removed from Cloudinary as well. Can be overridden.

Returns:

  • (Boolean)
[View source]

131
132
133
# File 'lib/cloudinary/carrier_wave.rb', line 131

def delete_remote?
  true
end

#download!(uri, *args) ⇒ Object

[View source]

2
3
4
5
6
7
8
9
10
11
12
13
# File 'lib/cloudinary/carrier_wave/remote.rb', line 2

def download!(uri, *args)
  return super unless self.cloudinary_should_handle_remote?
  if respond_to?(:process_uri)
    uri = process_uri(uri)
  else # Backward compatibility with old CarrierWave
    remote_url_unsafe_chars = /([^a-zA-Z0-9_.\-\/:?&=]+)/ # In addition allow query string characters: "?","&" and "="
    uri = URI.parse(Cloudinary::Utils.smart_escape(Cloudinary::Utils.smart_unescape(uri), remote_url_unsafe_chars))
  end
  return if uri.to_s.blank?
  self.original_filename = @cache_id = @filename = File.basename(uri.path).gsub(/[^a-zA-Z0-9\.\-\+_]/, '')
  @file = RemoteFile.new(uri, @filename)
end

#eagerObject

[View source]

128
129
130
# File 'lib/cloudinary/carrier_wave/process.rb', line 128

def eager
  @eager ||= self.all_processors.any?{|processor| processor[0] == :eager}
end

#filenameObject

[View source]

67
68
69
70
# File 'lib/cloudinary/carrier_wave.rb', line 67

def filename
  return nil if self.blank?
  return [self.full_public_id, self.format].reject(&:blank?).join(".")
end

#formatObject

[View source]

153
154
155
156
157
158
159
160
# File 'lib/cloudinary/carrier_wave/process.rb', line 153

def format
  format = Cloudinary::PreloadedFile.split_format(original_filename || "").last
  return format || "" if resource_type == "raw"
  format = requested_format || format || default_format

  format = format.to_s.downcase
  Cloudinary::FORMAT_ALIASES[format] || format
end

#full_public_idObject

[View source]

61
62
63
64
65
# File 'lib/cloudinary/carrier_wave.rb', line 61

def full_public_id
  return nil if self.blank?
  return self.my_public_id if self.stored_version.blank?
  return "v#{self.stored_version}/#{self.my_public_id}"
end

#is_main_uploader?Boolean

Returns:

  • (Boolean)
[View source]

19
20
21
# File 'lib/cloudinary/carrier_wave.rb', line 19

def is_main_uploader?
  self.class.version_names.blank?
end

#my_public_idObject

If the user overrode public_id, that should be used, even if it’s different from current public_id in the database. Otherwise, try to use public_id from the database. Otherwise, generate a new random public_id

[View source]

85
86
87
88
89
# File 'lib/cloudinary/carrier_wave.rb', line 85

def my_public_id
  @public_id ||= self.public_id
  @public_id ||= @stored_public_id
  @public_id ||= Cloudinary::Utils.random_public_id
end

#process!(new_file = nil) ⇒ Object

[View source]

120
121
122
# File 'lib/cloudinary/carrier_wave.rb', line 120

def process!(new_file=nil)
  # Do nothing
end

#public_idObject

public_id to use for uploaded file. Can be overridden by caller. Random public_id will be used otherwise.

[View source]

78
79
80
# File 'lib/cloudinary/carrier_wave.rb', line 78

def public_id
  nil
end

#recreate_versions!Object

[View source]

112
113
114
# File 'lib/cloudinary/carrier_wave.rb', line 112

def recreate_versions!
  # Do nothing
end

#rename(to_public_id = nil, overwrite = false) ⇒ Object

[View source]

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/cloudinary/carrier_wave.rb', line 91

def rename(to_public_id = nil, overwrite=false)
  public_id_overwrite = self.public_id
  to_public_id ||= public_id_overwrite
  if public_id_overwrite && to_public_id != public_id_overwrite
    raise CloudinaryException, "The public_id method was overridden and returns #{public_id_overwrite} - can't rename to #{to_public_id}"
  elsif to_public_id.nil?
    raise CloudinaryException, "No to_public_id given"
  end

  from_public_id = @stored_public_id || self.my_public_id
  return if from_public_id == to_public_id

  @public_id = @stored_public_id = to_public_id
  if self.resource_type == 'raw'
    from_public_id = [from_public_id, self.format].join(".")
    to_public_id = [to_public_id, self.format].join(".")
  end
  Cloudinary::Uploader.rename(from_public_id, to_public_id, :type=>self.storage_type, :resource_type=>self.resource_type, :overwrite=>overwrite)
  storage.store_cloudinary_identifier(@stored_version, [@public_id, self.format].join("."))
end

#requested_formatObject

[View source]

138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/cloudinary/carrier_wave/process.rb', line 138

def requested_format
  format_processor = self.all_processors.find{|processor| processor[0] == :convert}
  if format_processor
    # Explicit format is given
    format = Array(format_processor[1]).first
  elsif self.transformation.include?(:format)
    format = self.transformation[:format]
  elsif self.version_name.present?
    # No local format. The reset should be handled by main uploader
    uploader = self.model.send(self.mounted_as)
    format = uploader.format
  end
  format
end

#resource_typeObject

[View source]

203
204
205
# File 'lib/cloudinary/carrier_wave.rb', line 203

def resource_type
  @file.respond_to?(:resource_type) ? @file.resource_type : Cloudinary::Utils.resource_type_for_format(requested_format || original_filename || default_format)
end

#retrieve_from_cache!(new_file) ⇒ Object

[View source]

24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/cloudinary/carrier_wave/preloaded.rb', line 24

def retrieve_from_cache!(new_file)
  file = Cloudinary::CarrierWave::createRawOrPreloaded(new_file)
  if file
    @file = file
    @stored_version = @file.version
    @public_id = @stored_public_id = @file.public_id
    self.original_filename = sanitize(@file.original_filename)
    @cache_id = "unused" # must not be blank 
  else
    super
    @public_id = nil # allow overriding public_id
  end
end

#retrieve_from_store!(identifier) ⇒ Object

[View source]

27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/cloudinary/carrier_wave.rb', line 27

def retrieve_from_store!(identifier)
  # Workaround cloudinary-mongoid hack of setting column to _old_ before saving it.
  mongoid_blank = defined?(Mongoid::Extensions::Object) && self.is_a?(Mongoid::Extensions::Object) && identifier == "_old_"
  if identifier.blank? || mongoid_blank
    @file = @stored_version = @stored_public_id = nil
    self.original_filename = nil
  else
    @file = CloudinaryFile.new(identifier, self)
    @public_id = @stored_public_id = @file.public_id
    @stored_version = @file.version
    self.original_filename = sanitize(@file.filename)
  end
end

#sanitize(filename) ⇒ Object

[View source]

125
126
127
128
# File 'lib/cloudinary/carrier_wave.rb', line 125

def sanitize(filename)
  return nil if filename.nil?
  filename.gsub(SANITIZE_REGEXP, '_')
end

#set_or_yell(hash, attr, value) ⇒ Object

[View source]

53
54
55
56
# File 'lib/cloudinary/carrier_wave/process.rb', line 53

def set_or_yell(hash, attr, value)
  raise CloudinaryException, "conflicting transformation on #{attr} #{value}!=#{hash[attr]}" if hash[attr] && hash[attr] != value
  hash[attr] = value
end

#storage_typeObject

[View source]

199
200
201
# File 'lib/cloudinary/carrier_wave.rb', line 199

def storage_type
  @file.respond_to?(:storage_type) ? @file.storage_type : self.class.storage_type
end

#store!(new_file = nil) ⇒ Object

[View source]

162
163
164
165
166
167
168
169
170
171
172
# File 'lib/cloudinary/carrier_wave/process.rb', line 162

def store!(new_file=nil)
  super

  column = model.send(:_mounter, mounted_as).send(:serialization_column)
  original_value = model.read_attribute(column)
  identifiers = original_value.is_a?(Array) ? original_value : [original_value]

  identifiers.each do |identifier|
    retrieve_from_store!(identifier) unless identifier.nil?
  end
end

#stored_versionObject

[View source]

23
24
25
# File 'lib/cloudinary/carrier_wave.rb', line 23

def stored_version
  @stored_version
end

#tagsObject

[View source]

132
133
134
135
136
# File 'lib/cloudinary/carrier_wave/process.rb', line 132

def tags
  @tags ||= self.all_processors.select{|processor| processor[0] == :tags}.map(&:second).first
  raise CloudinaryException, "tags cannot be used in versions." if @tags.present? && self.version_name.present?
  @tags
end

#transformationObject

[View source]

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/cloudinary/carrier_wave/process.rb', line 58

def transformation
  return @transformation if @transformation
  @transformation = {}
  self.all_processors.each do |name, args, condition|

    if(condition)
      if condition.respond_to?(:call)
        next unless condition.call(self, :args => args)
      else
        next unless self.send(condition)
      end
    end

    case name
    when :convert # Do nothing. This is handled by format
    when :resize_to_limit
      set_or_yell(@transformation, :width, args[0])
      set_or_yell(@transformation, :height, args[1])
      set_or_yell(@transformation, :crop, :limit)
    when :resize_to_fit
      set_or_yell(@transformation, :width, args[0])
      set_or_yell(@transformation, :height, args[1])
      set_or_yell(@transformation, :crop, :fit)
    when :resize_to_fill
      set_or_yell(@transformation, :width, args[0])
      set_or_yell(@transformation, :height, args[1])
      set_or_yell(@transformation, :gravity, args[2].to_s.downcase)
      set_or_yell(@transformation, :crop, :fill)
    when :resize_and_pad
      set_or_yell(@transformation, :width, args[0])
      set_or_yell(@transformation, :height, args[1])
      set_or_yell(@transformation, :background, args[2].to_s.downcase)
      set_or_yell(@transformation, :gravity, args[3].to_s.downcase)
      set_or_yell(@transformation, :crop, :pad)
    when :scale
      set_or_yell(@transformation, :width, args[0])
      set_or_yell(@transformation, :height, args[1])
      set_or_yell(@transformation, :crop, :scale)
    when :crop
      set_or_yell(@transformation, :width, args[0])
      set_or_yell(@transformation, :height, args[1])
      set_or_yell(@transformation, :gravity, args[2].to_s.downcase)
      set_or_yell(@transformation, :crop, :crop)
    when :cloudinary_transformation
      args.each do
        |attr, value|
        set_or_yell(@transformation, attr, value)
      end
    else
      if args.blank?
        Array(send(name)).each do
          |attr, value|
          set_or_yell(@transformation, attr, value)
        end
      end
    end
  end
  @transformation
end

#url(*args) ⇒ Object

[View source]

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/cloudinary/carrier_wave.rb', line 41

def url(*args)
  if args.first && !args.first.is_a?(Hash)
    super
  else
    options = args.extract_options!
    if self.blank?
      url = self.default_url
      return url if !url.blank?
      public_id = self.default_public_id
      return nil if public_id.nil?
    else
      public_id = self.my_public_id
      options[:version] ||= self.stored_version
    end
    options = self.transformation.merge(options) if self.version_name.present?

    Cloudinary::Utils.cloudinary_url(public_id, {:format=>self.format, :resource_type=>self.resource_type, :type=>self.storage_type}.merge(options))
  end
end

#use_extended_identifier?Boolean

Use extended identifier format that includes resource type and storage type.

Returns:

  • (Boolean)
[View source]

146
147
148
# File 'lib/cloudinary/carrier_wave.rb', line 146

def use_extended_identifier?
  true
end