Friday, September 12, 2008

Changing attachment_fu Thumbnail Sizes

One of my side project involves photo uploads. Users were giving me feedback that the pictures were too small. No big deal, I thought, I'll just make them bigger. That's easy with attachment_fu; you just set up another thumbnail size in the photo model.

But how do you deal with all the other photos that have already been uploaded? A quick google search turned up this technique on Curtis Edmond's blog. Curtis left out a good bit of the implementation, so I'll spell it out here.

First, you need to create a folder called "attachment_fu_thumbnails" in the vendor/plugins directory. It's important to start the name of the folder with attachment_fu so that you will remember that you were monkeying around with the attachment_fu code later on.  (I currently have four attachment_fu hacks in my vendor directory via this method).

Then create a file called init.rb in the new folder. It should contain the following code, which I adapted from Curtis's blog:

# in vendor/plugins/attachment_fu_thumbnails/init.rb
Technoweenie::AttachmentFu::InstanceMethods.module_eval do
  def create_thumbnail_size(target_size)
    actual_size = self.attachment_options[:thumbnails][target_size]
    raise "this class doesn't have a thubnail size for #{target_size}" if actual_size.nil?
    tmp = self.create_temp_file
    self.create_or_update_thumbnail(tmp, target_size.to_s, actual_size)
    FileUtils.rm_rf(Dir.glob(File.join(RAILS_ROOT, 'tmp', 'attachment_fu', '*')))
  end
end

That code allows you to call the method
create_thumbnail_size(:size) 

on any object which has attachment_fu attachments.

The easiest way to do that is via a rake task. This code goes in a file called thumbnails.rake, which should be placed in /lib/tasks (this version creates two new thumbnails per object - :medium and :bigger).

#in /lib/tasks/thumbnails.rake
namespace :utils do
  desc "Generates :medium and :bigger thumbnails for all Pictures"
  task (:thumb => :environment) do
    images = Picture.find(:all)
    images.each do |i|
      if i.parent_id == nil # only create thumbs for base images
        i.create_thumbnail_size(:medium)
        i.create_thumbnail_size(:bigger)
        puts "Generated thumbs for Picture.id == #{i.id}"
      end
    end
  end
end

To create your new thumbnails, add the geometry string(s) to your image model and run

rake utils:thumb

from your app's home directory. Presto - all your old photos now have new thumbnail objects with corresponding files.

WARNING: This code, while it worked for me, is basically untested. Make sure you test it thoroughly before using in a production environment.

1 comments:

Jeremy Nicoll said...

Instead of specifying the names manually, an alternative could be to just loop through the available sizes like so:

i.class.attachment_options[:thumbnails].each { |k,v| i.create_thumbnail_size(k) }

Post a Comment