Module: Shrine::Plugins::Derivatives::AttacherMethods

Defined in:
lib/shrine/plugins/derivatives.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#derivativesObject

Returns the value of attribute derivatives.



90
91
92
# File 'lib/shrine/plugins/derivatives.rb', line 90

def derivatives
  @derivatives
end

Instance Method Details

#add_derivative(name, file, **options) ⇒ Object

Uploads a given file and adds it to the derivatives hash.

attacher.derivatives #=>
# {
#   thumb: #<Shrine::UploadedFile>,
# }
attacher.add_derivative(:cropped, cropped)
attacher.derivatives #=>
# {
#   thumb: #<Shrine::UploadedFile>,
#   cropped: #<Shrine::UploadedFile>,
# }


219
220
221
222
# File 'lib/shrine/plugins/derivatives.rb', line 219

def add_derivative(name, file, **options)
  add_derivatives({ name => file }, **options)
  derivatives[name]
end

#add_derivatives(files, **options) ⇒ Object

Uploads given hash of files and adds uploaded files to the derivatives hash.

attacher.derivatives #=>
# {
#   thumb: #<Shrine::UploadedFile>,
# }
attacher.add_derivatives(cropped: cropped)
attacher.derivatives #=>
# {
#   thumb: #<Shrine::UploadedFile>,
#   cropped: #<Shrine::UploadedFile>,
# }


201
202
203
204
205
# File 'lib/shrine/plugins/derivatives.rb', line 201

def add_derivatives(files, **options)
  new_derivatives = upload_derivatives(files, **options)
  merge_derivatives(new_derivatives)
  new_derivatives
end

#changeObject

Clears derivatives when attachment changes.

attacher.derivatives #=> { thumb: #<Shrine::UploadedFile> }
attacher.change(file)
attacher.derivatives #=> {}


444
445
446
447
448
# File 'lib/shrine/plugins/derivatives.rb', line 444

def change(*)
  result = super
  set_derivatives({})
  result
end

#create_derivatives(*args, storage: nil, **options) ⇒ Object

Calls processor and adds returned derivatives.

Attacher.derivatives_processor :my_processor do |original|
  # ...
end

attacher.create_derivatives(:my_processor)


183
184
185
186
# File 'lib/shrine/plugins/derivatives.rb', line 183

def create_derivatives(*args, storage: nil, **options)
  files = process_derivatives(*args, **options)
  add_derivatives(files, storage: storage)
end

#dataObject

Adds derivative data into the hash.

attacher.attach(io)
attacher.add_derivatives(thumb: thumb)
attacher.data
#=>
# {
#   "id" => "...",
#   "storage" => "store",
#   "metadata" => { ... },
#   "derivatives" => {
#     "thumb" => {
#       "id" => "...",
#       "storage" => "store",
#       "metadata" => { ... },
#     }
#   }
# }


398
399
400
401
402
403
404
405
406
407
408
409
# File 'lib/shrine/plugins/derivatives.rb', line 398

def data
  result = super

  if derivatives.any?
    result ||= {}
    result["derivatives"] = map_derivative(derivatives, transform_keys: :to_s) do |_, derivative|
      derivative.data
    end
  end

  result
end

#delete_derivatives(derivatives = self.derivatives) ⇒ Object

Deletes given hash of uploaded files.

attacher.delete_derivatives(thumb: uploaded_file)
uploaded_file.exists? #=> false


366
367
368
# File 'lib/shrine/plugins/derivatives.rb', line 366

def delete_derivatives(derivatives = self.derivatives)
  map_derivative(derivatives) { |_, derivative| derivative.delete }
end

#destroyObject

In addition to deleting the main file it also deletes any derivatives.

attacher.add_derivatives(thumb: thumb)
attacher.derivatives[:thumb].exists? #=> true
attacher.destroy
attacher.derivatives[:thumb].exists? #=> false


171
172
173
174
# File 'lib/shrine/plugins/derivatives.rb', line 171

def destroy
  super
  delete_derivatives
end

#get(*path) ⇒ Object

Convenience method for accessing derivatives.

photo.image_derivatives[:thumb] #=> #<Shrine::UploadedFile>
# can be shortened to
photo.image(:thumb) #=> #<Shrine::UploadedFile>


105
106
107
108
109
# File 'lib/shrine/plugins/derivatives.rb', line 105

def get(*path)
  return super if path.empty?

  get_derivatives(*path)
end

#get_derivatives(*path) ⇒ Object

Convenience method for accessing derivatives.

photo.image_derivatives.dig(:thumbnails, :large)
# can be shortened to
photo.image_derivatives(:thumbnails, :large)


116
117
118
119
120
121
122
# File 'lib/shrine/plugins/derivatives.rb', line 116

def get_derivatives(*path)
  return derivatives if path.empty?

  path = derivative_path(path)

  derivatives.dig(*path)
end

#initialize(derivatives: {}, **options) ⇒ Object

Adds the ability to accept derivatives.



93
94
95
96
97
98
# File 'lib/shrine/plugins/derivatives.rb', line 93

def initialize(derivatives: {}, **options)
  super(**options)

  @derivatives       = derivatives
  @derivatives_mutex = Mutex.new
end

#load_data(data) ⇒ Object

Loads derivatives from data generated by ‘Attacher#data`.

attacher.load_data({
  "id" => "...",
  "storage" => "store",
  "metadata" => { ... },
  "derivatives" => {
    "thumb" => {
      "id" => "...",
      "storage" => "store",
      "metadata" => { ... },
    }
  }
})
attacher.file        #=> #<Shrine::UploadedFile>
attacher.derivatives #=> { thumb: #<Shrine::UploadedFile> }


427
428
429
430
431
432
433
434
435
436
437
# File 'lib/shrine/plugins/derivatives.rb', line 427

def load_data(data)
  data ||= {}
  data   = data.dup

  derivatives_data = data.delete("derivatives") || data.delete(:derivatives) || {}
  @derivatives     = shrine_class.derivatives(derivatives_data)

  data = nil if data.empty?

  super(data)
end

#map_derivative(derivatives, **options, &block) ⇒ Object

Iterates through nested derivatives and maps results.

attacher.map_derivative(derivatives) { |path, file| ... }


465
466
467
# File 'lib/shrine/plugins/derivatives.rb', line 465

def map_derivative(derivatives, **options, &block)
  shrine_class.map_derivative(derivatives, **options, &block)
end

#merge_derivatives(new_derivatives) ⇒ Object

Deep merges given uploaded derivatives with current derivatives.

attacher.derivatives #=> { one: #<Shrine::UploadedFile> }
attacher.merge_derivatives(two: uploaded_file)
attacher.derivatives #=> { one: #<Shrine::UploadedFile>, two: #<Shrine::UploadedFile> }


285
286
287
288
289
290
# File 'lib/shrine/plugins/derivatives.rb', line 285

def merge_derivatives(new_derivatives)
  @derivatives_mutex.synchronize do
    merged_derivatives = deep_merge_derivatives(derivatives, new_derivatives)
    set_derivatives(merged_derivatives)
  end
end

#process_derivatives(processor_name = :default, source = nil, **options) ⇒ Object

Downloads the attached file and calls the specified processor.

Attacher.derivatives_processor :thumbnails do |original|
  processor = ImageProcessing::MiniMagick.source(original)

  {
    small:  processor.resize_to_limit!(300, 300),
    medium: processor.resize_to_limit!(500, 500),
    large:  processor.resize_to_limit!(800, 800),
  }
end

attacher.process_derivatives(:thumbnails)
#=> { small: #<File:...>, medium: #<File:...>, large: #<File:...> }


262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/shrine/plugins/derivatives.rb', line 262

def process_derivatives(processor_name = :default, source = nil, **options)
  # handle receiving only source file without a processor
  unless processor_name.respond_to?(:to_sym)
    source         = processor_name
    processor_name = :default
  end

  source ||= file!

  if source.is_a?(UploadedFile)
    source.download do |file|
      _process_derivatives(processor_name, file, **options)
    end
  else
    _process_derivatives(processor_name, source, **options)
  end
end

#promote(**options) ⇒ Object

In addition to promoting the main file, also promotes any cached derivatives. This is useful when these derivatives are being created as part of a direct upload.

attacher.assign(io)
attacher.add_derivative(:thumb, file, storage: :cache)
attacher.promote
attacher.stored?(attacher.derivatives[:thumb]) #=> true


147
148
149
150
# File 'lib/shrine/plugins/derivatives.rb', line 147

def promote(**options)
  super
  promote_derivatives
end

#promote_derivatives(**options) ⇒ Object

Uploads any cached derivatives to permanent storage.



153
154
155
156
157
158
159
160
161
162
163
# File 'lib/shrine/plugins/derivatives.rb', line 153

def promote_derivatives(**options)
  stored_derivatives = map_derivative(derivatives) do |path, derivative|
    if cached?(derivative)
      upload_derivative(path, derivative, **options)
    else
      derivative
    end
  end

  set_derivatives(stored_derivatives) unless derivatives == stored_derivatives
end

#remove_derivative(path, **options) ⇒ Object

Removes derivative with specified name from the derivatives hash.

attacher.derivatives #=> { one: #<Shrine::UploadedFile>, two: #<Shrine::UploadedFile> }
attacher.remove_derivative(:one) #=> #<Shrine::UploadedFile> (removed derivative)
attacher.derivatives #=> { two: #<Shrine::UploadedFile> }

Nested derivatives are also supported:

attacher.derivatives #=> { nested: { one: #<Shrine::UploadedFile>, two: #<Shrine::UploadedFile> } }
attacher.remove_derivative([:nested, :one]) #=> #<Shrine::UploadedFile> (removed derivative)
attacher.derivatives #=> { nested: { one: #<Shrine::UploadedFile> } }

The :delete option can be passed for deleting removed derivative:

attacher.derivatives #=> { one: #<Shrine::UploadedFile>, two: #<Shrine::UploadedFile> }
derivative = attacher.remove_derivatives(:two, delete: true)
derivative.exists? #=> false


358
359
360
# File 'lib/shrine/plugins/derivatives.rb', line 358

def remove_derivative(path, **options)
  remove_derivatives(path, **options).first
end

#remove_derivatives(*paths, delete: false) ⇒ Object

Removes derivatives with specified name from the derivatives hash.

attacher.derivatives
#=> { one: #<Shrine::UploadedFile>, two: #<Shrine::UploadedFile>, three: #<Shrine::UploadedFile> }

attacher.remove_derivatives(:two, :three)
#=> [#<Shrine::UploadedFile>, #<Shrine::UploadedFile>] (removed derivatives)

attacher.derivatives
#=> { one: #<Shrine::UploadedFile> }

Nested derivatives are also supported:

attacher.derivatives
#=> { nested: { one: #<Shrine::UploadedFile>, two: #<Shrine::UploadedFile>, three: #<Shrine::UploadedFile> } }

attacher.remove_derivatives([:nested, :two], [:nested, :three])
#=> [#<Shrine::UploadedFile>, #<Shrine::UploadedFile>] (removed derivatives)

attacher.derivatives
#=> { nested: { one: #<Shrine::UploadedFile> } }

The :delete option can be passed for deleting removed derivatives:

attacher.derivatives
#=> { one: #<Shrine::UploadedFile>, two: #<Shrine::UploadedFile>, three: #<Shrine::UploadedFile> }

two, three = attacher.remove_derivatives(:two, :three, delete: true)

two.exists?   #=> false
three.exists? #=> false


323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/shrine/plugins/derivatives.rb', line 323

def remove_derivatives(*paths, delete: false)
  removed_derivatives = paths.map do |path|
    path = Array(path)

    if path.one?
      derivatives.delete(path.first)
    else
      derivatives.dig(*path[0..-2]).delete(path[-1])
    end
  end

  set_derivatives derivatives

  delete_derivatives(removed_derivatives) if delete

  removed_derivatives
end

#set_derivatives(derivatives) ⇒ Object

Sets the given hash of uploaded files as derivatives.

attacher.set_derivatives(thumb: uploaded_file)
attacher.derivatives #=> { thumb: #<Shrine::UploadedFile> }


374
375
376
377
378
# File 'lib/shrine/plugins/derivatives.rb', line 374

def set_derivatives(derivatives)
  self.derivatives = derivatives
  set file # trigger model write
  derivatives
end

#upload_derivative(path, file, storage: nil, **options) ⇒ Object

Uploads the given file and deletes it afterwards.

hash = attacher.upload_derivative(:thumb, thumb)
hash[:thumb] #=> #<Shrine::UploadedFile>


238
239
240
241
242
243
244
245
246
# File 'lib/shrine/plugins/derivatives.rb', line 238

def upload_derivative(path, file, storage: nil, **options)
  path      = derivative_path(path)
  storage ||= derivative_storage(path)

  file.open    if file.is_a?(Tempfile)       # refresh file descriptor
  file.binmode if file.respond_to?(:binmode) # ensure binary mode

  upload(file, storage, derivative: path, delete: true, action: :derivatives, **options)
end

#upload_derivatives(files, **options) ⇒ Object

Uploads given hash of files.

hash = attacher.upload_derivatives(thumb: thumb)
hash[:thumb] #=> #<Shrine::UploadedFile>


228
229
230
231
232
# File 'lib/shrine/plugins/derivatives.rb', line 228

def upload_derivatives(files, **options)
  map_derivative(files) do |path, file|
    upload_derivative(path, file, **options)
  end
end

#url(*path, **options) ⇒ Object

Allows generating a URL to the derivative by passing the derivative name.

attacher.add_derivatives(thumb: thumb)
attacher.url(:thumb) #=> "https://example.org/thumb.jpg"


129
130
131
132
133
134
135
136
137
# File 'lib/shrine/plugins/derivatives.rb', line 129

def url(*path, **options)
  return super if path.empty?

  path = derivative_path(path)

  url   = derivatives.dig(*path)&.url(**options)
  url ||= default_url(**options, derivative: path)
  url
end