Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 394
Michael Fairley Avatar asked Sep 01 '11 08:09

Michael Fairley


5 Answers

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.

like image 176
Iain Avatar answered Nov 12 '22 13:11

Iain


Personally, I don't think you should really be putting this default in a model, since it's a view detail. In your (haml) view:

= image_tag(@image.avatar_url || 'none.png')

Or, create your own helper and use it like so:

= avatar_or_default(@image)

When things like this are hard in rails, it's often a sign that it's not exactly right.

like image 41
Peter Avatar answered Nov 12 '22 13:11

Peter


We solved this problem using draper: https://github.com/jcasimir/draper. Draper let us add a wrapper around our models (for use in views) that have access to helpers.

like image 31
Michael Fairley Avatar answered Nov 12 '22 13:11

Michael Fairley


Paperclip has an option to specify default url

has_attached_file :avatar, :default_url => '/images/.../missing_:style.png'

You can use this to serve default image' in case user has not uploaded avatar.

like image 42
socjopata Avatar answered Nov 12 '22 14:11

socjopata


Using rails active storage I solved this problem by doing this:

# Post.rb
def Post < ApplicationRecord
    has_one_attached :image

    def thumbnail
        self.image.attached? ? self.image.variant(resize: "150x150").processed.service_url : 'placeholder.png';
    end

    def medium
        self.image.attached? ? self.image.variant(resize: "300x300").processed.service_url : 'placeholder.png';
    end

    def large
        self.image.attached? ? self.image.variant(resize: "600x600").processed.service_url : 'placeholder.png';
    end
end

Then in your views simply call: <%= image_tag @post.thumbnail %>,

like image 35
Brad Avatar answered Nov 12 '22 14:11

Brad