El otro dia estube peleando para que mi aplicacion Rails pudiera hacer miniaturas de los PDFs.Actualmente utilizo PaperClip para gestionar mis archivos y leyendo la documentacion me di cuenta de que hay una manera muy sencilla (cuando se sabe) de hacerlo.
EL modelo sobre el que voy a trabajar es Documentos < AR:Base el cual tiene:
has_attached_file :archivo,
:styles => {
:thumb => ["100x100",:jpg],
:small => ["150x150",:jpg],
:micro => ["50x50",:png]},
:processors => lambda { |a| a.archivo.content_type.match(/pdf/) ? [ :compress ] : [ :thumbnail ] }
En processors utilizo lambda para elegir que procesador utilizar segun el tipo de archivo: compress para los pdfs y thumbnail para el resto.
Tambien tengo puesto que solo haga miniaturas para PDFs y imagenes en un filtro before_post_process
before_post_process :check_content_type_for_thumbnail
def check_content_type_for_thumbnail
#Si devuelve true,seguira el preproceso
return true if self.archivo.content_type.match(/image/)
return true if self.archivo.content_type.match(/pdf/)
return false
end
Una vez hecho esto, en vendor/plugins/paperclip/lib/paperclip/ puedes dejar las clases con tus propios procesadores.El mio es muy sencillo, lo unico que hace es ejecutar el convert de ImageMagick para generar la miniatura.
module Paperclip
class Compress < Processor
attr_accessor :file
def initialize file, options = {}, attachment = nil
Paperclip.log("[PAPERCLIP::Processor::Compress]Inicializando con #{file} #{options} #{attachment}")
super
@file = file
@options = options
@attachment = attachment
@format = options[:format]
@instance = @options[:instance]
@current_format = File.extname(@file.path)
@basename = File.basename(@file.path, @current_format)
end
def make
Paperclip.log("[PAPERCLIP::Processor::Compress] #{@options[:instance].class}")
@file.pos = 0 # Reset the file position incase it is coming out of a another processor
dst = Tempfile.new([@basename, @format].compact.join("."))
dst.binmode
args = "-resize #{@options[:geometry]} -format #{@format.to_s.gsub(".","")} #{@file.path}[0] #{dst.path}"
Paperclip.log("[PAPERCLIP::Processor::Compress] Voy a empezar a crear la miniatura #{args}")
begin
success = Paperclip.run('convert',args)
rescue PaperclipCommandLineError => e
Paperclip.log("#{e.inspect}")
raise PaperclipError, "Ha ocurrido un error generando la miniatura#{@basename} #{$!}" if @whiny_thumbnails
end
dst
end
end
end
Para poder utilizar el log, es necesario
Paperclip.options[:log] = true
Para recibir la instancia con la que estaba trabajando tuve que modificar vendor/plugins/paperclip/lib/paperclip/attachment.rb, en concreto post_process_styles :
- Paperclip.processor(processor).make(file, args, self)
+ Paperclip.processor(processor).make(file, args.merge(:instance => @instance),self)
Una vez hecho esto, a funcionar.Muy importante devolver el resultado en el Procesador, a mi se me olvido y estuve un buen rato peleandome con un error muy extraño en el .save del controlador que lo use.

EL modelo sobre el que voy a trabajar es Documentos < AR:Base el cual tiene:
has_attached_file :archivo,
:styles => {
:thumb => ["100x100",:jpg],
:small => ["150x150",:jpg],
:micro => ["50x50",:png]},
:processors => lambda { |a| a.archivo.content_type.match(/pdf/) ? [ :compress ] : [ :thumbnail ] }
En processors utilizo lambda para elegir que procesador utilizar segun el tipo de archivo: compress para los pdfs y thumbnail para el resto.
Tambien tengo puesto que solo haga miniaturas para PDFs y imagenes en un filtro before_post_process
before_post_process :check_content_type_for_thumbnail
def check_content_type_for_thumbnail
#Si devuelve true,seguira el preproceso
return true if self.archivo.content_type.match(/image/)
return true if self.archivo.content_type.match(/pdf/)
return false
end
Una vez hecho esto, en vendor/plugins/paperclip/lib/paperclip/ puedes dejar las clases con tus propios procesadores.El mio es muy sencillo, lo unico que hace es ejecutar el convert de ImageMagick para generar la miniatura.
module Paperclip
class Compress < Processor
attr_accessor :file
def initialize file, options = {}, attachment = nil
Paperclip.log("[PAPERCLIP::Processor::Compress]Inicializando con #{file} #{options} #{attachment}")
super
@file = file
@options = options
@attachment = attachment
@format = options[:format]
@instance = @options[:instance]
@current_format = File.extname(@file.path)
@basename = File.basename(@file.path, @current_format)
end
def make
Paperclip.log("[PAPERCLIP::Processor::Compress] #{@options[:instance].class}")
@file.pos = 0 # Reset the file position incase it is coming out of a another processor
dst = Tempfile.new([@basename, @format].compact.join("."))
dst.binmode
args = "-resize #{@options[:geometry]} -format #{@format.to_s.gsub(".","")} #{@file.path}[0] #{dst.path}"
Paperclip.log("[PAPERCLIP::Processor::Compress] Voy a empezar a crear la miniatura #{args}")
begin
success = Paperclip.run('convert',args)
rescue PaperclipCommandLineError => e
Paperclip.log("#{e.inspect}")
raise PaperclipError, "Ha ocurrido un error generando la miniatura#{@basename} #{$!}" if @whiny_thumbnails
end
dst
end
end
end
Para poder utilizar el log, es necesario
Paperclip.options[:log] = true
Para recibir la instancia con la que estaba trabajando tuve que modificar vendor/plugins/paperclip/lib/paperclip/attachment.rb, en concreto post_process_styles :
- Paperclip.processor(processor).make(file, args, self)
+ Paperclip.processor(processor).make(file, args.merge(:instance => @instance),self)
Una vez hecho esto, a funcionar.Muy importante devolver el resultado en el Procesador, a mi se me olvido y estuve un buen rato peleandome con un error muy extraño en el .save del controlador que lo use.