3

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?

sink66
  • 33
  • 4

1 Answers1

2
  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.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Janko
  • 8,985
  • 7
  • 34
  • 51
  • 1
    Q 1:It worked! Q 2 : My application wants to fix the image size at 120x120 and will not reprocess it later. So there is no need to keep other sizes. In this use case, for example, [carrierwave](https://github.com/carrierwaveuploader/carrierwave#adding-versions) seems to be able to resize the original image itself with `process resize_to_fit`. My usage may not match Shrine ... Thank you for answering. – sink66 Nov 24 '19 at 21:17
  • +1 for keeping the original file around. Algorithms improve as do image-encoding methods that allow us to reduce storage size or improve the quality of a rendered image, and having the original allows other new and exciting uses for them. – the Tin Man Nov 24 '19 at 21:35
  • I agree that keeping the original file around is best practice, but I also feel there should be a way to easily override this within Shrine. Sometimes you really don't care about the original and for space reasons, don't want to keep it. – andyrue Feb 11 '20 at 22:30
  • 1
    I will keep this in mind, and possibly add this ability in the future. For the time being, [this discussion](https://discourse.shrinerb.com/t/keep-original-file-after-processing/50) has some suggestions on how to achieve this with the current API. – Janko Feb 12 '20 at 15:51