Shrine: undefined method `resize_to_limit'

Created on 16 Apr 2018  路  10Comments  路  Source: shrinerb/shrine

image processing does not work. It raises undefined method `resize_to_limit' error in background jobs. I was using the repository version of shrine gem and this started happening after bundle update

System configuration

Ruby version:
ruby '2.4.2'

Shrine version:
shrine (2.10.1)

Most helpful comment

You probably updated ImageProcessing to version 1.0. The ImageProcessing gem has changed it's API in version 1.0, see the README.

TL;DR: This code

class ImageUploader < Shrine
  include ImageProcessing::MiniMagick

  plugin :processing
  plugin :versions

  process(:store) do |io, context|
    original = io.download

    size_800 = resize_to_limit(original, 800, 800)
    size_500 = resize_to_limit(original, 500, 500)
    size_300 = resize_to_limit(original, 300, 300)

    original.close!

    { original: io, large: size_800, medium: size_500, small: size_300 }
  end
end

now becomes

class ImageUploader < Shrine
  plugin :processing
  plugin :versions

  process(:store) do |io, context|
    original = io.download
    pipeline = ImageProcessing::MiniMagick.source(original)

    size_800 = pipeline.resize_to_limit!(800, 800)
    size_500 = pipeline.resize_to_limit!(500, 500)
    size_300 = pipeline.resize_to_limit!(300, 300)

    original.close!

    { original: io, large: size_800, medium: size_500, small: size_300 }
  end
end

All 10 comments

You probably updated ImageProcessing to version 1.0. The ImageProcessing gem has changed it's API in version 1.0, see the README.

TL;DR: This code

class ImageUploader < Shrine
  include ImageProcessing::MiniMagick

  plugin :processing
  plugin :versions

  process(:store) do |io, context|
    original = io.download

    size_800 = resize_to_limit(original, 800, 800)
    size_500 = resize_to_limit(original, 500, 500)
    size_300 = resize_to_limit(original, 300, 300)

    original.close!

    { original: io, large: size_800, medium: size_500, small: size_300 }
  end
end

now becomes

class ImageUploader < Shrine
  plugin :processing
  plugin :versions

  process(:store) do |io, context|
    original = io.download
    pipeline = ImageProcessing::MiniMagick.source(original)

    size_800 = pipeline.resize_to_limit!(800, 800)
    size_500 = pipeline.resize_to_limit!(500, 500)
    size_300 = pipeline.resize_to_limit!(300, 300)

    original.close!

    { original: io, large: size_800, medium: size_500, small: size_300 }
  end
end

@janko-m thank you, that fixed that problem but now I get this error

Shrine::InvalidFile (#<ImageProcessing::Builder:0x00007fcfbfb3a588 @options={:source=>#<Tempfile: (closed)>, :loader=>{}, :saver=>{}, :fo rmat=>nil, :operations=>[[:resize_to_limit, [#<Tempfile: (closed)>, 4746, 4746]]], :processor_class=>ImageProcessing::MiniMagick::Processor}> is not a valid IO object (it doesn't respond to #read, #eof?, #rewind, #close))

what else is changed in api?

It looks like it's trying to upload the image_processing::builder as a version instead of a processed image file. This can happen if you didn't use the the bang method (resize_to_limit!) for resize_to_limit in Janko's example above. 馃檪

@janko-m I think we should explicitly add a comment saying "Use bang method" or "Not bang method" whenever we answer questions and switch the methods. 馃槂

@hmistry Thanks for hopping in!

I think we should explicitly add a comment saying "Use bang method" or "Not bang method" whenever we answer questions and switch the methods.

I'm not sure what you mean by this. It's true that users that used ImageProcessing prior to 1.0 might be surprised that the "bang" doesn't mean "process in-place" anymore, and that processing in-place was actually removed in ImageProcessing 1.0. Is this way you meant? I'm thinking that we could just point anyone asking the same question to this ticket.

@janko-m Sorry I wasn't clear. I was thinking this is the third or forth time we've answered support questions where the user missed that we used the bang method or switched it. This has happened before the IP 1.0 release so nothing to do with the new release. My idea is that whenever we do a code sample that involves use of a bang method, we can add a comment explicitly stating use of bang method, or if we ask them to switch from bang to not bang or vice versa. Lets see if the comment catches their attention.

    size_800 = pipeline.resize_to_limit!(800, 800) #use bang method
    size_800 = pipeline.resize_to_limit(800, 800).call #use non-bang method

@janko-m @hmistry changed to use the bang method and error is gone now. But now when passing upload to background it raises this error

Error performing ImageUploadJob (Job ID : 8bb00f63-f8e8-475b-843c-6870af5de201) from DelayedJob(image) in 661.05ms: ArgumentError (wrong number of arguments (given 4, expected 3))

I checked everything and all seems fine, cannot figure it out

Can you post your uploader code here?

Here it is

class ImageUploader < Shrine
 plugin :processing
 plugin :versions
 plugin :validation_helpers
 plugin :upload_options, store: -> (io, context) do
  { metadata_directive: "REPLACE" } if io.is_a?(Shrine::UploadedFile)
 end

process(:store) do |io, context|
    original = io.download
    pipeline = ImageProcessing::MiniMagick.source(original)

    size_4746 = pipeline.resize_to_limit!(original, 4746, 4746)
    size_2160 = pipeline.resize_to_limit!(size_4746, 2160, 2160)
    size_2048 = pipeline.resize_to_limit!(size_2160, 2048, 2048)
    size_1024 = pipeline.resize_to_limit!(size_2048, 1024, 1024)

    original.close!


    {original: io, x4746: size_4746, x2160: size_2160, x2048: size_2048, x1024: size_1024 }
  end

 Attacher.validate do
  validate_mime_type_inclusion %w[image/jpeg image/png image/gif], message: "Image must be JPEG, PNG or GIF"
  validate_max_size 4.megabytes
  end
end

The new #resize_to_limit! method only accepts dimensions now, the source image is given separately in #source or #call. The direct translation of your code would be using #call instead of #source (notice that we're now calling #resize_to_limit without a bang)

    original = io.download
    pipeline = ImageProcessing::MiniMagick

    size_4746 = pipeline.resize_to_limit(4746, 4746).call(original)
    size_2160 = pipeline.resize_to_limit(2160, 2160).call(size_4746)
    size_2048 = pipeline.resize_to_limit(2048, 2048).call(size_2160)
    size_1024 = pipeline.resize_to_limit(1024, 1024).call(size_2048)

    original.close!

    { original: io, x4746: size_4746, x2160: size_2160, x2048: size_2048, x1024: size_1024 }

But I don't recommend generating thumbnails from other thumbnails anymore, because information is lost after a resize and the result ends up slightly blurry, though the new ImageProcessing versions remedy that by sharpening the thumbnails after resize. However, this way any information loss and now sharpening will be more and more multiplied.

I would recommend generating all thumbnails from the same source image (notice the #source and #resize_to_limit! with a bang now):

    original = io.download
    pipeline = ImageProcessing::MiniMagick.source(image)

    size_4746 = pipeline.resize_to_limit!(4746, 4746)
    size_2160 = pipeline.resize_to_limit!(2160, 2160)
    size_2048 = pipeline.resize_to_limit!(2048, 2048)
    size_1024 = pipeline.resize_to_limit!(1024, 1024

    original.close!

    { original: io, x4746: size_4746, x2160: size_2160, x2048: size_2048, x1024: size_1024 }

This will be slower, but thumbnails will be more correct.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cilim picture cilim  路  10Comments

thebravoman picture thebravoman  路  8Comments

printercu picture printercu  路  10Comments

technodrome picture technodrome  路  4Comments

musaffa picture musaffa  路  7Comments