Default_url in Paperclip Broke with Asset Pipeline Upgrade - ruby-on-rails-3

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).

:default_url => ActionController::Base.helpers.asset_path('missing_:style.png')
Then put the default images in app/assets/images/

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.

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">

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.

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

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' }

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.

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.

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, ...

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

Related

How to store file with unicode characters using paperclip

I'm using paperclip gem to process some images and store them to Amazon S3. Each image represents person's name. I want to add support for names with unicode characters as well, but I can't make it work because of paperclip fails to upload a file with unicode characters in its name.
I can't just change Ñ to N before uploading, because then I'll overwrite an image that was uploaded with letter N.
Eg.
Two users: NUÑO and NUNO. I can't just tell paperclip to upload NUÑO.jpg as NUNO.jpg because that will overwrite previous NUNO.jpg.
Here's my pretty much standard production/staging environment configuration:
config.paperclip_defaults = {
:storage => :s3,
:url => ':s3_domain_url',
:path => 'assets/:class/:id/:style.:extension',
:s3_credentials => {
:bucket => ENV['AWS_BUCKET'],
:access_key_id => ENV['AWS_ACCESS_KEY_ID'],
:secret_access_key => ENV['AWS_SECRET_ACCESS_KEY_ID']
}
}
And here's related class with image attachment:
class NameSpread < ActiveRecord::Base
(...)
has_attached_file :rendered_image,
default_url: lambda { |attach| attach.instance.processing_image },
path: lambda { |attach| attach.instance.save_path },
styles: { (..) },
processors: [ :name_spread_processor ],
default_style: :spread
(...)
end
Here's save_path method:
def save_path
if Rails.env.production? || Rails.env.staging?
"assets/:class/#{gender}/#{name}/:style.jpg"
else
"#{Rails.root}/public/assets/:class/#{gender}/#{name}/:style.jpg"
end
end
This is the part that gets messed up: #{name}
Any ideas?
After two days of debugging, I found the solution.
I updated from ruby 1.9.2 to 2.0.0 and now everything works...

How can we restrict file uploads with valid file type but invalid content-type - Rails

In my Rails web application, I have to upload audio and video files and for validating against invalid file types, I have used jquery-validation engine and I could do the same successfully. But, if I create a text file and change the extension from .txt to .mp3, e.g. test.txt to test.mp3, it will be taken as valid by jquery validation engine as the file extension is valid for an audio.
I want to check the content type also. When I opened the test.mp3 in a player, it showed me an error message Stream contains no data. I want this kind of validation to be performed in the interface. Is it possible in Rails?
I'm using,
Rails 3.2.13
Ruby 2.0.0-dev
Hope anyone can help me out. Thanks :)-
I recommend you to check paperclip gem its a file attachment library for Active Record. This library is very straightforward to use and make validations with each content type. For example if you want to validate an Image you can by the next validation:
class User < ActiveRecord::Base
attr_accessible :avatar
has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
validates_attachment :avatar,
:presence => true, :content_type => { :content_type => "image/jpg" },
:size => { :in => 0..500.kilobytes }
end
Hope it helps.

best way to process images already on S3 (rails)

I have a set of images on Amazon S3, and I'd like to automatically generate thumbnails for them to serve on my site.
I've considered Cloudinary, but it seems that I'd have to copy over all my images to Cloudinary servers first. I want to keep them on S3.
I've considered Dragonfly, but it seems that Dragonfly only works with files I'd upload after installing Dragonfly. I already have uploaded all my files.
What's a good solution for me? I'm in a Rails environment (rails 3.2).
Thanks!
If it's just a 'set of images' it's not really that well structured. You're better off reorganizing the way you store and manage images.
Try Paperclip.
class ModelName < ActiveRecord::Base
attr_accessible :image #more here
has_attached_file :image, :styles => { :large => "450x450>", :medium => "300x300>", :thumb => "150x150>" },
:storage => :s3,
:s3_credentials => "#{Rails.root}/config/s3.yml",
:path => "people/:style/:id/:filename",
:s3_protocol => "https"
def original_image_url
image.url
end
def large_image_url
image.url(:large)
end
def medium_image_url
image.url(:medium)
end
def small_image_url
image.url(:thumb)
end
#etc
end
Then simply do this to assign an existing image to an existing instance through the console:
require 'uri'
#instance.image = open(URI::encode(url))
#instance.save
# s3 will now contain the images in the appropriate sizes in the format specified above.
Since the original will also be saved, I'd advise to then delete the 'set of images' on s3 you started with, otherwise you'll be duplicating them.
I was wrong about Dragonfly. You can use Dragonfly on already-uploaded files. I'm using it on my project and it's working out great.

Paperclip/AWS S3: attachment url is always default even though file is properly uploaded to S3

When I create a user model the avatar.png file gets properly uploaded to S3 in the defined path. Problem is that, when I try to "read/download" the user.avatar.url it always gives the default path i.e. default avatar.
My user.rb has this:
attr_accessible :avatar
has_attached_file :avatar,
:storage => :s3,
:bucket => "/avatars",
:s3_credentials => {
:access_key_id => ENV['S3_KEY'],
:secret_access_key => ENV['S3_SECRET']
},
:path => "/avatars/:filename",
:default_url => "https://s3.amazonaws.com/avatars/default.png"
In my view I have:
user.avatar.url #<--- Which outputs https://s3.amazonaws.com/avatars/default.png
Any ideas how to get the right url and the right avatar (which does exists in S3)?
Or how to debug the attachment search path (i.e. the path where paperclip searches the file)?
The problem was that attachments file_name attribute didn't get saved and that was due to this line:
attr_accessor :avatar_file_name
Removing that line fixed the problem.

Paperclip S3 image path issue

I've just upgraded from Rails 3.1 to Rails 3.2.6 and my paperclip photo paths are now broken on production.
photo.rb
if Rails.env == "production"
has_attached_file :image,
:storage => :s3,
:s3_credentials => S3_CREDENTIALS,
:url => "/app/public/system/images/:id/:style/:basename.:extension",
I need the resulting path to be like so: http://s3.amazonaws.com/photoramblr/app/public/system/images/5/thumb_large/image.jpg
but instead the above url settings result in: http://s3.amazonaws.com/photoramblr/app/public/app/public/system/images/5/thumb_large/image.jpg
I've also tried setting the paperclip url to :url => "/system/images/:id/:style/:basename.:extension" but that resulted in this url: http://s3.amazonaws.com/photoramblr/images/5/thumb_large/image.jpg
Any thoughts on how I can set this properly?
UPDATE: Well, I still don't understand how it's working, but I 'fixed' this by just moving the files to the location it was looking in.
Try adding a path parameter replacing the url parameter and specifying the path under the bucket name where your file will be stored and the URL will be constructed from the bucket and the path supplied. Here is a link to paperclip s3 docs for further details. If you supply a url parameter, it is treated relative to your "app/public". That explains why you're resulting image path doubles "app/public". Ryan Bate's paperclip tutorial also explains this behaviour.
In your case your code will be as shown below;
if Rails.env.production?
has_attached_file :image,
:storage => :s3,
:s3_credentials => S3_CREDENTIALS,
:path => "app/public/system/images/:id/:style/:basename.:extension",
Your resulting link will be (I'm assuming your bucket name is photorambler from your link); s3.amazonaws.com/photorambler/app/public/system/images/5/thumb_large/image.jpg