How can I reference images in the asset pipeline from a model?

Michael Fairley picture Michael Fairley · Sep 1, 2011 · Viewed 19.1k times · Source

I have a model with a method to return a url to a person's avatar that looks like this:

 def avatar_url
   if self.avatar?
     self.avatar.url # This uses paperclip
   else
     "/images/avatars/none.png"
   end
 end

I'm in the midst of upgrading to 3.1, so now the hard-coded none image needs be referenced through the asset pipeline. In a controller or view, I would just wrap it in image_path(), but I don't have that option in the model. How can I generate the correct url to the image?

Answer

Iain picture Iain · Oct 24, 2012

I struggled with getting this right for a while so I thought I'd post the answer here. Whilst the above works for a standard default image (i.e. same one for each paperclip style), if you need multiple default styles you need a different approach.

If you want to have the default url play nice with the asset pipeline and asset sync and want different default images per style then you need to generate the asset path without fingerprints otherwise you'll get lots of AssetNotPrecompiled errors.

Like so:

   :default_url => ActionController::Base.helpers.asset_path("/missing/:style.png", :digest => false)

or in your paperclip options:

   :default_url => lambda { |a| "#{a.instance.create_default_url}" }

and then an instance method in the model that has the paperclip attachment:

def create_default_url
   ActionController::Base.helpers.asset_path("/missing/:style.png", :digest => false)
end

In this case you can still use the interpolation (:style) but will have to turn off the asset fingerprinting/digest.

This all seems to work fine as long as you are syncing assets without the digest as well as those with the digest.