Repository: rails/rails
File: activestorage/app/models/active_storage/variant.rb (Ruby)

Code before:
# can then produce on-demand.
#
# When you do want to actually produce the variant needed, call +processed+. This will check that the variant
# has already been processed and uploaded to the service, and, if so, just return that. Otherwise it will perform
# the transformations, upload the variant to the service, and return itself again. Example:
#
#   avatar.variant(resize_to_limit: [100, 100]).processed.url
#
# This will create and process a variant of the avatar blob that's constrained to a height and width of 100.
# Then it'll upload said variant to the service according to a derivative key of the blob and the transformations.
#
# You can combine any number of ImageMagick/libvips operations into a variant, as well as any macros provided by the
# ImageProcessing gem (such as +resize_to_limit+):
#
#   avatar.variant(resize_to_limit: [800, 800], monochrome: true, rotate: "-90")
#
# Visit the following links for a list of available ImageProcessing commands and ImageMagick/libvips operations:
#
# * {ImageProcessing::MiniMagick}[https://github.com/janko-m/image_processing/blob/master/doc/minimagick.md#methods]
# * {ImageMagick reference}[https://www.imagemagick.org/script/mogrify.php]
# * {ImageProcessing::Vips}[https://github.com/janko-m/image_processing/blob/master/doc/vips.md#methods]
# * {ruby-vips reference}[http://www.rubydoc.info/gems/ruby-vips/Vips/Image]
class ActiveStorage::Variant
  attr_reader :blob, :variation
  delegate :service, to: :blob

  def initialize(blob, variation_or_variation_key)
    @blob, @variation = blob, ActiveStorage::Variation.wrap(variation_or_variation_key)
  end

  # Returns the variant instance itself after it's been processed or an existing processing has been found on the service.
  def processed
    process unless processed?
    self
  end

  # Returns a combination key of the blob and the variation that together identifies a specific variant.
  def key
    "variants/#{blob.key}/#{Digest::SHA256.hexdigest(variation.key)}"
  end

  # Returns the URL of the blob variant on the service. See {ActiveStorage::Blob#url} for details.
  #
  # Use <tt>url_for(variant)</tt> (or the implied form, like +link_to variant+ or +redirect_to variant+) to get the stable URL
  # for a variant that points to the ActiveStorage::RepresentationsController, which in turn will use this +service_call+ method
  # for its redirection.
  def url(expires_in: ActiveStorage.service_urls_expire_in, disposition: :inline)
    service.url key, expires_in: expires_in, disposition: disposition, filename: filename, content_type: content_type
  end

  alias_method :service_url, :url

Review comment (refactor):
@fleck this seems to duplicate the definition at line 128 of this same file as now I see these warnings:
```
activestorage/app/models/active_storage/variant.rb:128: warning: method redefined; discarding old filename
activestorage/app/models/active_storage/variant.rb:59: warning: previous definition of filename was here
activestorage/app/models/active_storage/variant.rb:128: warning: method redefined; discarding old content_type
activestorage/app/models/active_storage/variant.rb:59: warning: previous definition of content_type was here
```

Code after:
# can then produce on-demand.
#
# When you do want to actually produce the variant needed, call +processed+. This will check that the variant
# has already been processed and uploaded to the service, and, if so, just return that. Otherwise it will perform
# the transformations, upload the variant to the service, and return itself again. Example:
#
#   avatar.variant(resize_to_limit: [100, 100]).processed.url
#
# This will create and process a variant of the avatar blob that's constrained to a height and width of 100.
# Then it'll upload said variant to the service according to a derivative key of the blob and the transformations.
#
# You can combine any number of ImageMagick/libvips operations into a variant, as well as any macros provided by the
# ImageProcessing gem (such as +resize_to_limit+):
#
#   avatar.variant(resize_to_limit: [800, 800], monochrome: true, rotate: "-90")
#
# Visit the following links for a list of available ImageProcessing commands and ImageMagick/libvips operations:
#
# * {ImageProcessing::MiniMagick}[https://github.com/janko-m/image_processing/blob/master/doc/minimagick.md#methods]
# * {ImageMagick reference}[https://www.imagemagick.org/script/mogrify.php]
# * {ImageProcessing::Vips}[https://github.com/janko-m/image_processing/blob/master/doc/vips.md#methods]
# * {ruby-vips reference}[http://www.rubydoc.info/gems/ruby-vips/Vips/Image]
class ActiveStorage::Variant
  attr_reader :blob, :variation
  delegate :service, to: :blob
  delegate :content_type, :filename, to: :specification

  def initialize(blob, variation_or_variation_key)
    @blob, @variation = blob, ActiveStorage::Variation.wrap(variation_or_variation_key)
  end

  # Returns the variant instance itself after it's been processed or an existing processing has been found on the service.
  def processed
    process unless processed?
    self
  end

  # Returns a combination key of the blob and the variation that together identifies a specific variant.
  def key
    "variants/#{blob.key}/#{Digest::SHA256.hexdigest(variation.key)}"
  end

  # Returns the URL of the blob variant on the service. See {ActiveStorage::Blob#url} for details.
  #
  # Use <tt>url_for(variant)</tt> (or the implied form, like +link_to variant+ or +redirect_to variant+) to get the stable URL
  # for a variant that points to the ActiveStorage::RepresentationsController, which in turn will use this +service_call+ method
  # for its redirection.
  def url(expires_in: ActiveStorage.service_urls_expire_in, disposition: :inline)
    service.url key, expires_in: expires_in, disposition: disposition, filename: filename, content_type: content_type
  end