Default_url in Paperclip Broke with Asset Pipeline Upgrade
Asked Answered
S

10

33

I'm using Paperclip and have a default_url option like this for one of my attachments:

:default_url => '/images/missing_:style.png'

The asset pipeline obviously doesn't like this since the directories moved. What's the best way to handle this? I have two styles for this picture (:mini and :thumb).

Snot answered 10/3, 2012 at 12:49 Comment(1)
does the accepted solution still work for you? As per my comment below, I still haven't found a solution for thisSpill
N
45
:default_url => ActionController::Base.helpers.asset_path('missing_:style.png')

Then put the default images in app/assets/images/

Norfolk answered 19/3, 2012 at 18:24 Comment(8)
this not works in production env, following error raised: attachments/:class/:attachment/:style/missing.jpg isn't precompiled actionpack (3.1.4) lib/sprockets/helpers/rails_helper.rb:147:in `digest_for'Aret
@Aret and what do you do in production?Substitution
Sorry, I actually remember running into an issue when we pushed to production but now I don't remember what it was or what the resolution was. On my latest project, I just used ':default_url => "/assets/avatar_defaults/default_:style_avatar.png' and store the defaults under app/assets/images/avatar_defaults/. That has been working fine in all cases.Norfolk
@Norfolk Rails, by default, doesn't compile assets when running in production (it's slow). You need to precompile assets before pushing to production: bundle exec rake assets:precompileMacassar
This solution does not work for me in Rails 4.1 in either my development or production (Heroku) environments. In both environments, my images are in app/assets/images, and when I open a Rails console and try ActionController::Base.helpers.asset_path('missing.png'), it prints out the properly fingerprinted path (/assets/missing-longmd5hash.png). However, the default URLs returned by Model.attachment.url for instances of Model without an attachment only return /missing.png (doesn't have the /assets prefix or the fingerprint at the end). Any ideas what might be going wrong?Spill
How I solved the problem with production environments in Rails 3.2 was by passing :digest => false to asset_path. You see, it doesn't need to find the non-existent file called "missing_:style.png" if we don't require a digest.Nottinghamshire
If this solution doesn't work see my comment on github github.com/thoughtbot/paperclip/issues/… . In short: just wrap #asset_path in lambda.Brodie
@Brodie Using his lambda method was the only working solution for me as well running S3 storage on Heroku deploy (Rails 4.2)Hyperacidity
P
25

Tested only on Rails 4.

To make it work in production, we have to pass the name of an existing file to the asset_path helper. Passing a string containing a placeholder like "missing_:style.png" therefore doesn't work. I used a custom interpolation as a workaround:

# config/initializers/paperclip.rb
Paperclip.interpolates(:placeholder) do |attachment, style|
  ActionController::Base.helpers.asset_path("missing_#{style}.png")
end

Note that you must not prefix the path with images/ even if your image is located in app/assets/images. Then use it like:

# app/models/some_model.rb
has_attached_file(:thumbnail,
                  :default_url => ':placeholder',
                  :styles => { ... })

Now default urls with correct digest hashes are played out in production.

The default_url option also takes a lambda, but I could not find a way to determine the requested style since interpolations are only applied to the result of the lambda.

Polyphemus answered 25/9, 2013 at 15:11 Comment(4)
This works for me. What a nice and cool solution. How did you figure that out? I never knew they implement "interpolates" methodSophi
Thanks. You can find out a little bit more about Paperclip interpolations on this wiki page.Polyphemus
Sorry, but I'm a bit new in rails and I don't know how to use this approach. Where I have to put the interpolation code? Thanks in advance.Scot
@halbano: You can create a paperclip initializer (config/initializers/paperclip.rb) and simply paste the code in there.Polyphemus
S
15

Just make sure that in your views all your paperclip images are rendered with image_tag.

<%= image_tag my_model.attachment.url(:icon) %>

That way, all of paperclip's :crazy :symbol :interpolation will have happened to the url string before Rails tries to resolve it to an asset in the pipeline.

Also, make sure your :default_url is asset compatible...if missing_icon.png is at app/assets/images/missing_icon.png, then :default_url should be simply "missing_:style.png"

<%= image_tag my_model.attachment.url(:icon) %>
# resolves to...
<%= image_tag "missing_icon.png" %>
# which in development resolves to...
<img src="/assets/missing_icon.png">
Sultanate answered 19/6, 2012 at 18:6 Comment(1)
Essentially, all you need to do is ensure your default_url setting doesn't start with a slash. The default default_url is /:attachment/:style/missing.png, so just changing that to :attachment/:style/missing.png will cause everything to start working in production (with precompiled assets) and continue working in dev...Choirboy
U
8

I got the error(even for a single style) at assets:precompile with

:default_url => ActionController::Base.helpers.asset_path('missing.png')

So I hooked with a method like this

# supposing this is for avatar in User model

has_attached_file :avatar,
   :styles => {..},    
   :default_url => lambda { |avatar| avatar.instance.set_default_url}

def set_default_url
  ActionController::Base.helpers.asset_path('missing.png')
end

I didn't try for multiple styles, but this works for my situation.

Ulrikeulster answered 7/9, 2012 at 4:40 Comment(2)
Worked properly for rails 4.1Hydrocellulose
Or all in the lambda: default_url: -> (a) { ActionController::Base.helpers.asset_path('missing.jpg') }Laminitis
K
3

this works for me:

has_attached_file :avatar, :styles => { :small => "52x52",
:medium => "200x200>", :large=> "300x300", :thumb => "100x100>" },
                              :default_url => "missing_:style.png"

just place images in your assets/images folder named: missing_large.png, missing_medium.png, missing_small.png and missing_thumb.png

Katiekatina answered 8/3, 2014 at 23:44 Comment(1)
Thank you! no one else explained that the :style would just take it from the previous description!!!!Terisateriyaki
E
2

In rails 4.0.0 and paperclip 4.1.1 this worked for me:

has_attached_file :avatar,
  styles: { medium: '300x300#', small: '100x100#', thumb: '25x25#' },
  default_url: ->(attachment) { 'avatar/:style.gif' },
  convert_options: { all: '-set colorspace sRGB -strip' }
Eurypterid answered 16/4, 2014 at 8:47 Comment(0)
A
1

I ended up having to use something like the following.

DEFAULT_URL = "#{Rails.configuration.action_controller.asset_host}#{Rails.configuration.assets.prefix}/:attachment/:style/missing.png"
has_attached_file :art, :styles => { :large => "398x398#", :medium => "200x200#", :small=>"100x100#", :smaller=>"50x50#", :smallest=>"25x25"}, :path=>"images/:attachment/:id/:style/:basename.:extension", :default_url => DEFAULT_URL

I statically compile the assets and was getting an error in production, this helped me.

Abnegate answered 19/11, 2014 at 16:21 Comment(0)
B
1

In your model file, change this line:

has_attached_file :avatar, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"

by removing this:

/images/

Create a folder for each style, in this example medium and thumb, in assests/images and place an image called missing.png there (or whatever name you want it to have of course, as long as it matches the file name in the model)

Worked for me.

Blossomblot answered 6/10, 2016 at 11:30 Comment(0)
R
0

I've solved this problem by using a custom interpolator.

The problem from other solutions that suggest using

:default_url => ActionController::Base.helpers.asset_path('missing_:style.png')

is that you will get an error saying "missing_style.png" is not precompiled.

I created an initializer with the following code:

module Paperclip
  module AssetPipeline
    module Interpolator
      def self.interpolate(pattern, *args)
        ActionController::Base.helpers.asset_path Paperclip::Interpolations.interpolate(pattern, *args)
      end
    end
  end
end

Then in my model I would do:

has_attached_file :image, interpolator: Paperclip::AssetPipeline::Interpolator, ...
Rotation answered 12/1, 2014 at 19:18 Comment(0)
A
0

Just remove the / from /images/pic.png: images/pic.png

Abdel answered 8/12, 2014 at 11:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.