Topic: Help DRY my attachment_fu helpers

I'm using attachment_fu to upload pictures and resize them to various sizes (three in fact - thumb, mini, and picture). I came up with a little helper that returns either the path to the image or a standard "no image" image if the user didn't upload one. Since there are three sizes, there are three helpers. Surely there is a way to combine these three methods into one.

(An easier way to accomplish the same objective is also welcome, but I'd still like to know how to fix this code.)

module ApplicationHelper
  def path_to_thumb(owner)
    unless owner.picture.nil?
      owner.picture.public_filename(:thumb)
    else
      "/images/no_thumb.jpg"
    end
  end
 
  def path_to_mini(owner)
    unless owner.picture.nil?
      owner.picture.public_filename(:mini)
    else
      "/images/no_mini.jpg"
    end
  end
   
  def path_to_picture(owner)
    unless owner.picture.nil?
      owner.picture.public_filename
    else
      "/images/no_picture.jpg"
    end
  end
end

Re: Help DRY my attachment_fu helpers

Here's how I'd do it:

module ApplicationHelper
  def path_to_picture(owner, type = nil)
    unless owner.picture.nil?
      owner.picture.public_filename(*[type].compact)
    else
      "/images/no_#{type || :picture}.jpg"
    end
  end
end

You can then call path_to_picture(owner, :thumb), for instance, but path_to_picture(owner) will continue to function as it currently does. If you want, you can make path_to_thumb and path_to_mini shortcuts to this:

def path_to_thumb(owner); path_to_picture(owner, :thumb); end
def  path_to_mini(owner); path_to_picture(owner, :mini ); end

Last edited by manitoba98 (2008-01-26 09:13:23)

Re: Help DRY my attachment_fu helpers

Thanks. Is there a way to write a method that would automatically generate path_to_#{type} methods that look for /images/no_#{type}.jpg files without having to define the shortcuts?

Re: Help DRY my attachment_fu helpers

You'd have to define them somehow. You could do this:

module ApplicationHelper
  def path_to_picture(owner, type = nil)
    # (...)
  end

  [:thumb, :mini].each do |type|
    define_method "path_to_#{type}" { |owner| path_to_picture(owner, type) }
  end
end


Which makes the code slightly simpler...I can't think of how to make it much easier, but some Rails guru might have some wisdom.

Re: Help DRY my attachment_fu helpers

As a general rule of thumb, if a helper method isn't generating markup, there's a good chance it belongs in a model. I would take manitoba98's original method and put it in the owner's model. It will be less error prone, easier to refactor, and easier to remember than using a helper.

path_to_picture(owner, :thumb)
# becomes...
owner.picture_path(:thumb)
owner.picture_path(:mini)
owner.picture_path

Re: Help DRY my attachment_fu helpers

OK. That makes sense, but I have several different models that can all act as owners of the picture using:

#picture.rb
belongs_to :owner, :polymorphic => true

#item.rb, folder.rb, user.rb, etc. all have a picture
has_one :picture, :as => :owner


Or am I misusing polymorphic associations?

Re: Help DRY my attachment_fu helpers

Try extracting the duplicated code into a module, and include it in each model that uses that code. Something similar to this should work:

# models/user.rb, models/folder.rb, etc...

class User < ActiveRecord::Base
 
  include HasOnePicture

end


# lib/has_one_picture.rb:

module HasOnePicture

  def self.included(base)
    base.class_eval do
     
      has_one :picture, :as => :owner
     
      def picture_path(thumbnail = nil)
        if picture
          picture.public_filename(thumbnail)
        else
          "/images/no_#{thumbnail || :picture}.jpg"
        end
      end

    end
  end

end

Re: Help DRY my attachment_fu helpers

Thanks. That will work perfectly.

Re: Help DRY my attachment_fu helpers

One more problem - I broke the method out into a module in /lib, and now rake db:create doesn't work. It bombs out with a "#42000Unknown database 'ynp_development'" error. If I remove the include statement from the User model, it works again. (The user model is a modified restful_authentication model). Any idea why this is happening?


Here are the details:
http://www.railsforum.com/viewtopic.php?id=15218

Last edited by damoncali (2008-02-05 15:15:59)