Reputation: 485
I've been at this one for a while now. Using this RailsCast I have been able to modify it to work with CarrierWave - at least in theory. I am attempting to allow the user to crop their profile photo and then upload it to S3 using CarrierWave. Here is what works so far:
So, here's the code I've got. Here's the model:
attr_accessor :crop_x, :crop_y, :crop_w, :crop_h, :original_width, :original_height
attr_accessible :avatar, :remove_avatar
after_update :reprocess_avatar, :if => :cropping?
mount_uploader :avatar, ProfileBaseUploader
def cropping?
!crop_x.blank? && !crop_y.blank? && !crop_w.blank? && !crop_h.blank?
end
private
def reprocess_avatar
avatar.process!
avatar.recreate_versions!
end
Pretty boiler plate - the crop_x, etc attributes are assigned from the crop view. I have confirmed that these are getting passed in and assigned correctly and that the reprocess_avatar method is getting called.
Here is my uploader code:
include CarrierWave::MiniMagick
include CarrierWaveDirect::Uploader
storage :fog
require 'guid'
process :cropper
process :store_best_geometry
version :tiny_thumb do
process :resize_to_limit => [50, 50]
end
version :thumb do
process :resize_to_limit => [200, 200]
end
version :large do
process :resize_to_fit => [500, 500]
end
def extension_white_list
%w(jpg jpeg gif png)
end
def filename
@name ||= "#{secure_token}.#{file.extension}" if original_filename.present?
end
def store_best_geometry
manipulate! do |img|
if model
model.original_width = img['width']
model.original_height = img['height']
end
img = yield(img) if block_given?
img
end
end
def cropper
return unless model.cropping?
manipulate! do |img|
img = img.crop("#{model.crop_x}x#{model.crop_y}+#{model.crop_w}+#{model.crop_h}")
img
end
end
protected
def secure_token
var = :"@#{mounted_as}_secure_token"
model.instance_variable_get(var) or model.instance_variable_set(var, Guid.new)
end
I think that the process! and recreate_versions! methods are simply not functioning properly but I have no clue as to why. I don't have any errors that I can provide (if anybody knows how I could generate one I would gladly do so). I know that the store_best_geometry method is working great. Can't say the same thing for cropper.
Any ideas?
Upvotes: 2
Views: 2168
Reputation: 485
Like a bad plane crash, there are a lot of things that I did incorrectly.
First, I had the arguments for crop in the wrong order. In my question, you'll notice I had:
img.crop('[x offset]x[y offset]+[width]+[height]')
The correct order is:
img.crop('[width]x[height]+[x offset]+[y offset]')
So that was problem one. Trying to do it in the wrong order was throwing an error (dug into the console to find it) about the geometry being provided as invalid.
Next problem: breaking a yield chain with my cropper method and returning a STRING instead of an IMAGE. Turns out that the crop method returns a string. Look at the original cropper method:
def cropper
return unless model.cropping?
manipulate! do |img|
img = img.crop("#{model.crop_x}x#{model.crop_y}+#{model.crop_w}+#{model.crop_h}")
img
end
end
Oops! Last thing being returned there is a string. Turns out, the correct way is to just call the method on the image directly:
def cropper
return unless model.cropping?
manipulate! do |img|
img.crop("#{model.crop_w}x#{model.crop_h}+#{model.crop_x}+#{model.crop_y}")
img = yield(img) if block_given?
img
end
end
The final thing I was doing wrong - and this was a complete amateur hour mistake - was not making some key attributes accessible. In my infinite wisdom, I assumed that attr_accessor would make the attributes accessible. Nope. I had to modify my model to make the crop_x, crop_y, crop_w, and crop_h arguments accessible.
attr_accessor :crop_x, :crop_y, :crop_w, :crop_h, :original_width, :original_height
attr_accessible :avatar, :remove_avatar, :crop_x, :crop_y, :crop_w, :crop_h
after_update :reprocess_avatar, :if => :cropping?
A last note, not critical but handy to know. I did not need to call process! as recreate_versions! does that for me.
Hope this helps at least one person out there.
Upvotes: 9