How do I get Paperclip to recognize custom processors instead of just pushing styles through to thumbnail? - ruby-on-rails

I am not having any problem getting the custom processor to load, however when I try to call it from has_attached_file, paperclip ignores it, and instead just runs thumbnail.
model
has_attached_file :file,
:styles => { :web => "some input" },
:processors => [ :custom ],
:url => ":class/:id/:style/:basename.:extension",
:path => ":class/:id/:style/:basename.:extension"
:storage => :s3
As simple a processor as can be made just to show that the processor has been run
processor.rb
module Paperclip
class Custom < Processor
attr_accessor :input
def initialize(file, options = {}, attachment = nil)
super
#basename = File.basename(file.path, File.extname(file.path))
end
def make
dst = Tempfile.new([ #basename, 'jpg' ].compact.join("."))
dst
end
end
end
But instead when I check the saved record it returns instance variables from thumbnail
>record.file.styles
{:web=>
#<Paperclip::Style:0x00000102f185d0
#attachment=
http://s3.amazonaws.com/bucket/model/id/base_name/file_name.jpg,
#format=nil,
#geometry="some_input",
#name=:web,
#other_args={}>}
I must be missing something in either writing the processor or calling it. Any idea what is going on here?

Have you tried something like this?
has_attached_file :file,
:styles => {
:my_super_style => {:geometry => "100x100#", :foo => "bar", :processors => [:custom]}
},

Have you put in the right place?
lib/paperclip_processors/custom.rb

:styles => { :web => "some input" },
:processors => [ :custom ],
should be:
:styles => {
:web => {:geometry => "some input", :processors => [:custom]},

Related

URL issue: paperclip-av-transcoder

I am trying to implement paperclip-av-transcoder gem. I have checked everything but not able to find what I am doing wrong here. I'm writing steps which I have followed.
Added into gemfile
--> gem 'paperclip-av-transcoder'
Added into my model
--> has_attached_file :video_file, :styles => {
:medium => { :geometry => "640x480", :format => 'mp4' },
:thumb => { :geometry => "100x100#", :format => 'jpg', :time => 10 }
}, :processors => [:transcoder]
--> validates_attachment_content_type :video_file, :content_type => /\Avideo\/.*\Z/
created schema to add column name
"video_file_meta"
In my view file
video_tag(video.video_file.url, controls: true, autobuffer: true, size: "320x240")
I have checked video in public/system folder it is properly saved I am able to see that video there but I am not able to see that in my view file.
Video Url -> /system/videos/video_files/000/000/003/original/tingtong_464.mp4?1497851104
I am sharing screens to show how it looks in the browser.
Everything from my point is correct, except Paperclip requires at least one field in database - *_file_name (for you it's video_file_file_name), but you didn't added it and Paperclip can't construct url properly. Read more https://github.com/thoughtbot/paperclip#usage
Currently working model file code:
has_attached_file :video_file, :styles => {
:medium => { :geometry => "500x500", :format => 'jpg' },
:thumb => { :geometry => "100x100", :format => 'jpg' }
}, :processors => [:transcoder]
validates_attachment_content_type :video_file,
:content_type => [
"video/mp4",
"video/quicktime",
"video/3gpp",
"video/x-ms-wmv",
"video/mov",
"video/flv",
],
:message => "Sorry! We do not accept the attached file type"
I guess I am not resizing my video file in any other video format so it is working properly.

Paperclip security validation error mp4

I am using Paperclip to upload videos and keep getting a Security Validation error about the content type
The error when saving an mp4 to my model class is "content type discovered from file command: video/mp4. See documentation to allow this combination."
The save looks like this
AssignmentEventVideo.create(video: "https://s3-ap-southeast-2.amazonaws.com/dev/upload/0c857445-09ad-44b6-bbfa-810a9974a501/ScreenCaptureProject4.mp4")
The model class
class AssignmentEventVideo < ActiveRecord::Base
has_attached_file :video, :styles => {
:medium => { :geometry => "640x480", :format => 'mp4' },
:android => { :geometry => "640x480", :format => 'webm'},
:mobile => { :geometry => "300x300", :format => 'png', :time => 2 },
:thumb => { :geometry => "100x100#", :format => 'png', :time => 2 }
}
validates_attachment_content_type :video, content_type: ['video/mp4']
end
If have tried disabling validation all together with the code below but it still throws the error
do_not_validate_attachment_file_type :video
I have confirmed that the file command is return the correct type with
file -b --mime ScreenCaptureProject3.mp4
which returns
video/mp4; charset=binary
The save is working fine for another model class that accepts images and checks content using
validates_attachment_content_type :photo, content_type: /\Aimage\/.*\Z/
I'm not sure where to turn next - except to recreate the class and change the column name to something that doesn't clash with video?
Hope someone can help!
Thanks katafrakt - you got me on the right path.
I was using a presigned_post and uploading to S3 using JQuery FileUploader. This was not setting the Content-Type and I was getting back a binary/octet type that Paperclip didn't know how to deal with.
I set content_type on the presigned post, which stores the right meta data in S3 and all is well.

Paperclip post processing conversion does not update file_name, content_type attributes

I would like to restrict File uploads to images only, and convert them automatically to .png. To do so, I use this class:
class ImageAttachment < ActiveRecord::Base
attr_accessible :file, :file_file_name, :file_content_type, :file_file_size
validates_attachment :file,
:content_type => { :content_type => ["image/jpg", "image/tiff", "image/png"] }
has_attached_file :file,
:styles => { :original => ["100%", :png],
:large => ["500x500", :png],
:medium => ["150x150", :png],
:thumb => ["75x100", :png]
},
:default_url => "/system/missing_thumb.png"
end
As I understand, the :styles => { :original => ["100%", :png], ...} should convert all uploaded files that pass validation to .png files. Therefore, I expect the following things to happen when uploading a file example.tiff:
convert the file to .png
change the file name accordingly to example.png
change the content type accordingly to "image/png"
Here's a spec I use:
it "should convert all image types to .png" do
test_file = File.new(Rails.root + "spec/fixtures/images/test.tiff")
attachment = ImageAttachment.create :file => test_file
attachment.file.url.should == "some/paperclip/path/.../test.png"
attachment.file_file_name.should == "test.png"
attachment.file_content_type.should == "image/png"
end
The first assertion is true, and I can also see ImageMagick output in the terminal,
but attachment.file_file_name still returns example.tiff, and attachment.file_content_type returns "image/tiff".
Is my assumption that paperclip automatically updates the file_file_name and the file_content_type attributes wrong?
If so, how would I best do this on my own?

Generate Thumbnail From pdf in rails paperclip

How can I generate the first page of a pdf as a thumbnail in paperclip?
I tried a lot but it's not working
has_attached_file :book_url, :styles => {
:thumb => "100x100#",
:small => "150x150>",
:medium => "200x200" }
This is giving the name of the pdf as a link but it's not giving the first page of the pdf
<%= link_to 'My PDF', #book.book_url.url %>
Tadas' answer is right, but for those who need more context, you can do something like this: The model below only creates thumbnails for certain kinds of files (e.g. it doesn't make thumbnails of audio files), but does make thumbnails for pdfs, image files, and video files:
class Record < ActiveRecord::Base
print self # for logging on heroku
belongs_to :user
# Ensure user has provided the required fields
validates :title, presence: true
validates :file_upload, presence: true
validates :description, presence: true
# Use the has_attached_file method to add a file_upload property to the Record
# class.
has_attached_file :file_upload,
# In order to determine the styles of the image we want to save
# e.g. a small style copy of the image, plus a large style copy
# of the image, call the check_file_type method
styles: lambda { |a| a.instance.check_file_type },
processors: lambda {
|a| a.is_video? ? [ :ffmpeg ] : [ :thumbnail ]
}
# Validate that we accept the type of file the user is uploading
# by explicitly listing the mimetypes we are willing to accept
validates_attachment_content_type :file_upload,
:content_type => [
"video/mp4",
"video/quicktime",
"image/jpg",
"image/jpeg",
"image/png",
"image/gif",
"application/pdf",
"audio/mpeg",
"audio/x-mpeg",
"audio/mp3",
"audio/x-mp3",
"file/txt",
"text/plain",
"application/doc",
"application/msword",
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/vnd.ms-powerpoint"
],
:message => "Sorry! We do not accept the attached file type"
# Before applying the Imagemagick post processing to this record
# check to see if we indeed wish to process the file. In the case
# of audio files, we don't want to apply post processing
before_post_process :apply_post_processing?
# Helper method that uses the =~ regex method to see if
# the current file_upload has a content_type
# attribute that contains the string "image" / "video", or "audio"
def is_image?
self.file_upload.content_type =~ %r(image)
end
def is_video?
self.file_upload.content_type =~ %r(video)
end
def is_audio?
self.file_upload.content_type =~ /\Aaudio\/.*\Z/
end
def is_plain_text?
self.file_upload_file_name =~ %r{\.(txt)$}i
end
def is_excel?
self.file_upload_file_name =~ %r{\.(xls|xlt|xla|xlsx|xlsm|xltx|xltm|xlsb|xlam|csv|tsv)$}i
end
def is_word_document?
self.file_upload_file_name =~ %r{\.(docx|doc|dotx|docm|dotm)$}i
end
def is_powerpoint?
self.file_upload_file_name =~ %r{\.(pptx|ppt|potx|pot|ppsx|pps|pptm|potm|ppsm|ppam)$}i
end
def is_pdf?
self.file_upload_file_name =~ %r{\.(pdf)$}i
end
def has_default_image?
is_audio?
is_plain_text?
is_excel?
is_word_document?
end
# If the uploaded content type is an audio file,
# return false so that we'll skip audio post processing
def apply_post_processing?
if self.has_default_image?
return false
else
return true
end
end
# Method to be called in order to determine what styles we should
# save of a file.
def check_file_type
if self.is_image?
{
:thumb => "200x200>",
:medium => "500x500>"
}
elsif self.is_pdf?
{
:thumb => ["200x200>", :png],
:medium => ["500x500>", :png]
}
elsif self.is_video?
{
:thumb => {
:geometry => "200x200>",
:format => 'jpg',
:time => 0
},
:medium => {
:geometry => "500x500>",
:format => 'jpg',
:time => 0
}
}
elsif self.is_audio?
{
:audio => {
:format => "mp3"
}
}
else
{}
end
end
end
I think I once got it working by enforcing a file type, e.g.
:thumb => ["100x100#", :png]
of course it's not ideal, because it enforces this filetype for every upload
Thanks a million to #duhaime for his beautiful answer.
Since this is the most complete source of information I found to have PDF attached, I'd like to document it further:
Requirements:
imagemagick
ghostscript (I forgot about this one)
(optional) ffmpeg if you want to handle video files
Also I replaced has_default_image? and apply_post_processing? with the single:
def can_thumbnail?
self.check_file_type.try(:{], :thumb).present?
end
Finally I created a method for the not-thumbable attachments:
def thumb
return self.file.url(:thumb) if self.can_thumbnail?
if self.is_video?
'/thumb/video.png'
else
'/thumb/default.png'
end
end
But thanks again #duhaime

How to set Paperclip style work only if contenttype is image?

I am using the following:
has_attached_file :file,:styles => { :thumbnail => '320x240!'},:url => "/images/:attachment/:id/:style/:basename.:extension",:path => ":rails_root/public/images/:attachment/:id/:style/:basename.:extension"
validates_attachment_content_type :file, :content_type => [ 'image/gif', 'image/png', 'image/x-png', 'image/jpeg', 'image/pjpeg', 'image/jpg' ]
To upload both images and video. If I use :style =>{} then image does not upload. I want to use :style method only if content type of file is image.
You can use condition inside of lambda, sorry about ugly formatting:
has_attached_file :file, :styles => lambda
{ |a|
if a.instance.is_image?
{:thumbnail => "320x240!"}
end
}
def is_image?
return false unless asset.content_type
['image/jpeg', 'image/pjpeg', 'image/gif', 'image/png', 'image/x-png', 'image/jpg'].include?(asset.content_type)
end
Update 2016:
Most upvoted answer still works, but you need to return an empty hash if it's not of the expected type (eg. a PDF that you don't want to process instead of an image), else you'll run into TypeError - can't dup NilClass issues.
Sample using a ternary for terseness:
has_attached_file :file, :styles => lambda { |a| a.instance.is_image? ? {:thumbnail => "320x240!"} : {} }

Resources