ruby-on-railsrubyimage-processingimagemagickshrine

How to upload while resizing the original image itself in Shrine


I use Shrine in a Ruby on Rails application to create the process of resizing and uploading images to storage.

My current code is:


image_uploader.rb

require "image_processing/mini_magick"

class ImageUploader < Shrine
  plugin :derivatives

  Attacher.derivatives_processor do |original|
    magick = ImageProcessing::MiniMagick.source(original)
    {
      resized: magick.resize_to_limit!(120, 120)
    }
  end

end

user.rb

class User < ApplicationRecord
  include ImageUploader::Attachment(:image)
  before_save :image_resize

  def image_resize
    self.image_derivatives!
  end
end

I implemented it while reading the official documentation, but this is not desirable in two ways.

  1. Requires trigger in model code. Can it be completed with only image_uploader.rb?
  2. Access to images generated with this code requires a "resized" prefix(e.g. @user.image(:resized).url), and the original image will also remain in storage. I want to process the original image itself.

Is there a way to upload while solving these two issues?


Solution

    1. You can add the following patch, which will trigger derivatives creation as part of promoting cached file to permanent storage:

      # put this in your initializer
      class Shrine::Attacher
        def promote(*)
          create_derivatives
          super
        end
      end
      
    2. You can just override the model method that retrieves the attached file to return the resized version. You can use the included plugin to do this for all models using this uploader:

      class ImageUploader < Shrine
        # ...
        plugin :included do |name|
          define_method(name) { super(:resized) }
        end
      end
      

    As for the second question: It will still keep the original file in the storage, but just return the resized version instead by default. It's generally better to do this in a view decorator instead.

    You always want to keep the original file in the storage, because you never know when you'll need to reprocess it. It can happen that you find your current resizing logic not to be ideal for certain filetypes and sizes, in which case you'll need to regenerate the resized version for previous attachments. And you wouldn't be able to do that if you didn't have the original file anymore.