1 Comment By Damon on Jun 27 in Website, Headache, and Rubyonrails.

Attachment_fu is a great plugin by Rick Olsen (a.k.a. techno-weenie). I use this plugin for one of the sites I maintain. I recently ran into a situation where I needed to regenerate the thumbnails for all the uploaded images. Attachment_fu provides no built-in support for this, so I had to get creative. A quick search on Google revealed a post by Michael D. Ivey that seemed like a reasonable thing to do, but was not sufficient by itself. So in this blog, I plan to cover the steps I took to automate the regeneration of thumbnails when you are using attachment_fu.

So the jist of the problem was that I wanted attachment_fu to generate an additional thumbnail when saving files. The easy route would have been to forget about regenerating anything and consider it an acceptable loss to not have this additional thumbnail with all the previously uploaded images. However, that would have caused some cosmetic damage to the site. Thus, regeneration was needed.

Original has_attachment configuration

class GalleryImage < ActiveRecord::Base
[...]
has_attachment :storage => :file_system,
:path_prefix => 'public/gallery_images',
:thumbnails => { :archive => '119>x88>', :thumb => '64>x48>', :small => '340>x255>', :medium => '640>x480>', :large => '1024>x768>' },
:content_type => :image,
:max_size => 5.megabytes
[...]
end

New has_attachment configuration

class GalleryImage < ActiveRecord::Base
[...]
has_attachment :storage => :file_system,
:path_prefix => 'public/gallery_images',
:thumbnails => { :archive => '119>x88>', :thumb => '64>x48>', :small => '340>x255>', :medium => '640>x480>', :large => '1024>x768>', :square => [50,50] },
:content_type => :image,
:max_size => 5.megabytes
[...]
end

Note the addition of the :square => [50,50]. That's the new guy. It's probably worth noting that I wanted to generate a thumbnail that was perfectly square to maintain a cosmetic consistently to the page. I actually created a patch for attachment_fu to do this in case anyone else might find it useful. Here ya go.

square_thumbnails_for_attachment_fu.patch

## This patch enables the use of square thumbnails.
--- a/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/processors/rmagick_processor.rb
+++ b/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/processors/rmagick_processor.rb
@@ -41,7 +41,7 @@ module Technoweenie # :nodoc:
           size = size.first if size.is_a?(Array) && size.length == 1 && !size.first.is_a?(Fixnum)
           if size.is_a?(Fixnum) || (size.is_a?(Array) && size.first.is_a?(Fixnum))
             size = [size, size] if size.is_a?(Fixnum)
-            img.thumbnail!(*size)
+            size[0] == size[1] ? img.crop_resized!(*size) : img.thumbnail!(*size)
           else
             img.change_geometry(size.to_s) { |cols, rows, image| image.resize!(cols<1 ? 1 : cols, rows<1 ? 1 : rows) }
           end

Note: Once patched, it will create square thumbnails when you provide a thumbnail parameter such like :my_squre_thumb => [50,50]. If the array contains the same parameters, attachment_fu will make a square thumbnail and not squeeze/squish it.

As I mentioned, I needed to patch attachment_fu to do my own thing. This was because one of the problems I quickly ran into was that the method used to determine if something was "thumbnailable" checked for the presence of a "parent id". Since I had pre-existing images, they all had "parent ids" and thus I would just receive an error that said the following:

Can't create a thumbnail if the content type is not an image or there is no parent_id column

Alright, so after some investigation, I found out that it had to do with the thumbnailable? method. Since I wanted a solution that was automated, I decided to create a rake task. This rake task would apply a patch to attachment_fu when executed, regenerate all the thumbnails, and then reverse the patch.

regenerate_thumbnails_runtime.patch

# Diables the check for a nil parent_id.
+++ ../vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu.rb
--- ../vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu.rb
@@ -220,7 +220,7 @@ module Technoweenie # :nodoc:
 
       # Returns true/false if an attachment is thumbnailable.  A thumbnailable attachment has an image content type and the parent_id attri
       def thumbnailable?
-        image? && respond_to?(:parent_id) && parent_id.nil?
+        image? && respond_to?(:parent_id) #&& parent_id.nil?
       end
 
       # Returns the class used to create new thumbnails for this attachment.

Alright, so now that I had a patch, I needed a rake task. I decided to actually create two rake tasks. One for my local development environment and one for my production server.

regenerate_thumbs.rake

namespace :regenerate_thumbs do
  desc "Regenerate thumbnails for development environment"
  task :development do
    puts "Regenerating the thumbnails..."
    # Patch attachment_fu
    system "patch -p1 --no-backup-if-mismatch #{Rails.root}/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu.rb < #{Rails.root}/lib/patches/regenerate_thumbnails_runtime.patch"
    # Regenerate thumbnails
    system "script/runner -e development 'Administration.regenerate_gallery_thumbnails'"
    # Unpatch attachment_fu
    system "patch -p1 -R --no-backup-if-mismatch #{Rails.root}/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu.rb < #{Rails.root}/lib/patches/regenerate_thumbnails_runtime.patch"
  end
 
  desc "Regenerate thumbnails for production environment"
  task :production do
    puts "Regenerating the thumbnails..."
    # Patch attachment_fu
    system "patch -p1 --no-backup-if-mismatch #{Rails.root}/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu.rb < #{Rails.root}/lib/patches/regenerate_thumbnails_runtime.patch"
    # Regenerate thumbnails
    system "script/runner -e production 'Administration.regenerate_gallery_thumbnails'"
    # Unpatch attachment_fu
    system "patch -p1 -R --no-backup-if-mismatch #{Rails.root}/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu.rb < #{Rails.root}/lib/patches/regenerate_thumbnails_runtime.patch"
  end
end

Alright, now we've gotten as far as creating a runtime patch and a rake task. One thing that you'll note in the rake task is that I use script/runner to execute a method in my Administration model. So to explain, I have an Administration model where I put miscellaneous tasks like session cleanup, thumbnail regeneration, and other admin-related tasks. You can do something similar or create the self.regenerate_gallery_thumbnails method below in an existing model.

app/models/Administration.rb

class Administration < ActiveRecord::Base
  def self.regenerate_gallery_thumbnails
    GalleryImage.find(:all).each do |p|
      next if p.gallery_id.nil?
      puts "Regenerating thumbnails for #{p.filename}"
      begin
        temp_file = p.create_temp_file
      rescue
        puts "Failed to create temp file for #{p.id}"
        nil
      end
      p.attachment_options[:thumbnails].each { |suffix, size|
        begin
          p.create_or_update_thumbnail(temp_file, suffix, *size)
        rescue
          puts "Failed to process #{p.id}"
          nil
        end
      }
    end
  end
 
end

Alright, that about sums it up. Now all I had to do is cross my fingers and make sure I had a backup of the database and images. Then it was just a matter of running one of the following commands, depending on my desired environment:

rake regenerate_thumbs:development

or

rake regenerate_thumbs:production

Given that this took me a few hours to figure out, I decided to post on here in case it might help someone else out. Maybe someday Rick will introduce this functionality into a version of attachment_fu, keep your fingers crossed and good luck.

Current Rating: 5.0 rating from 1 vote

  • Current rating is 5
  •  
  •  
  •  
  •  
  •  

One Response to "Regenerating Thumbnails in Attachment_Fu"

Default_avatar_thumb

Jaime Iniesta

August 20, 2008 at 04:29 am

For me the problem is just the opposite: attachment_fu always regenerates the thumbnails after each update of my Photo models, even if you didn’t upload a new file, say, you just updated its title.

So I don’t understand why you need to do all that… just do a model.save and you’re done with thumbnails regeneration. At least, on the latest versions of attachment_fu.

Comments are Closed

Name: (Required)
Website:
Comment:
Remember my info