I have this model for pictures attached to another model (Work
):
class WorkPicture < ActiveRecord::Base
after_initialize :default_values
after_update :reprocess_picture, if: :cropping_changed?
belongs_to :work, inverse_of: :pictures
has_attached_file :picture, styles: lambda { |attachment| { big: { geometry: "1500x>", format: :png },
thumb: attachment.instance.thumb_options } },
url: "/pictures/:hash.:extension",
hash_secret: ENV["PAPERCLIP_SECRET_KEY"]
validates_attachment :picture, presence: true,
content_type: { content_type: /image/ }
scope :illustrative, -> { where(is_cover: false) }
# Default values
def default_values
self.is_cover = false if self.is_cover.nil?
self.crop_x = 0 if self.crop_x.nil?
self.crop_y = 0 if self.crop_y.nil?
end
def thumb_options
return { geometry: "", format: :png, convert_options: "-crop 360x222+#{crop_x.to_i}+#{crop_y.to_i}" }
end
private
def cropping_changed?
self.crop_x_changed? || self.crop_y_changed?
end
def reprocess_picture
picture.reprocess!
end
end
These pictures serve a dual purpose: if is_cover
is set to false
, they're displayed in the gallery page of the work in question. If is_cover
is set to true
, they're cropped and used as "icons" for the work in question in a page that lists all works.
On the work edit page you're allowed to change the x and y coordinates of the cropping. This means that the image should be reprocessed once the new coordinates come in, so that the correct area is shown.
To do this, I set up two attributes on the model, crop_x
and crop_y
, which store the position of the cropping window. Through after_update
, I first check if those coordinates have been changed and, if so, I tell Paperclip to reprocess the image to crop it correctly.
When running this code, execution enters an endless loop. I think I've identified the cause of this: after_update
doesn't clear the ActiveRecord::Dirty
attributes (e.g. self.crop_x_changed?
) to make it more useful to the developer, but when I call reprocess!
on the picture Paperclip itself makes changes to my model and calls save
, which in turn causes the after_update
callback to be triggered again. Since self.crop_x_changed?
and self.crop_y_changed?
are still true
from the beginning of this chain (this is because they seem to only be cleared once after_update
has been run), this causes my code to call reprocess!
again, which continues this endless loop.
I've tried many similar variations of this code, but all seem to either loop endlessly or just fail. Is there a way I can make my code perform this function correctly?