Как я могу заставить CarrierWave добавить правильное расширение к имени файла в зависимости от его содержимого? Например, если я загружаю файл "logo" (файл PNG без расширения), CarrierWave должен сохранить его как "logo.png". А файл "img.gif" (файл JPG с неверным расширением) соответственно сохранить как "img.jpg".
CarrierWave и правильное расширение файла в зависимости от его содержимого
Ответы (2)
Есть несколько вещей, которые вы можете сделать, в зависимости от того, используете ли вы process
или version
для этого.
Если это версия, в вики несущей волны есть способ сделать условные версии. https://github.com/jnicklas/carrierwave/wiki/How-to%3A-Do-conditional-processing
version :big, :if => :png? do
process ...
end
protected
def png?(new_file)
new_file.content_type.include? 'png'
end
Если вы используете метод process
, вы можете взглянуть на это: https://gist.github.com/995663.
Добавьте их в свой код, чтобы обойти ограничения, которые есть у process
.
# create a new "process_extensions" method. It is like "process", except
# it takes an array of extensions as the first parameter, and registers
# a trampoline method which checks the extension before invocation
def self.process_extensions(*args)
extensions = args.shift
args.each do |arg|
if arg.is_a?(Hash)
arg.each do |method, args|
processors.push([:process_trampoline, [extensions, method, args]])
end
else
processors.push([:process_trampoline, [extensions, arg, []]])
end
end
end
# our trampoline method which only performs processing if the extension matches
def process_trampoline(extensions, method, args)
extension = File.extname(original_filename).downcase
extension = extension[1..-1] if extension[0,1] == '.'
self.send(method, *args) if extensions.include?(extension)
end
Затем вы можете использовать это для вызова того, что раньше было процессом, выборочно для каждого типа файла.
PNG = %w(png)
JPG = %w(jpg jpeg)
GIF = %w(gif)
def extension_white_list
PNG + JPG + GIF
end
process_extensions PNG, :resize_to_fit => [1024, 768]
process_extensions JPG, :...
process_extensions GIF, :...
Проблема в том, чтобы определить правильный контент в первую очередь. Carrierwave использует гем MimeType, который определяет его MIME-тип из расширения. Поскольку в вашем случае расширение неверно, вам нужен альтернативный способ получения правильного типа mime. Это лучшее решение, которое я смог придумать, но оно зависит от способности читать файл изображения с помощью драгоценного камня RMagick.
Я столкнулся с той же проблемой, и мне пришлось переопределить метод set_content_type по умолчанию для моего загрузчика. Это предполагает, что у вас есть гем Rmagick в вашем Gemfile, так что вы можете получить правильный MIME-тип, читая изображение, а не делая наилучшее предположение.
Примечание. Это особенно полезно, если изображение используется программой Prawn, которая поддерживает только изображения JPG и PNG.
Класс загрузчика:
process :set_content_type
def set_content_type #Note we are overriding the default set_content_type_method for this uploader
real_content_type = Magick::Image::read(file.path).first.mime_type
if file.respond_to?(:content_type=)
file.content_type = real_content_type
else
file.instance_variable_set(:@content_type, real_content_type)
end
end
Модель изображения:
class Image < ActiveRecord::Base
mount_uploader :image, ImageUploader
validates_presence_of :image
validate :validate_content_type_correctly
before_validation :update_image_attributes
private
def update_image_attributes
if image.present? && image_changed?
self.content_type = image.file.content_type
end
end
def validate_content_type_correctly
if not ['image/png', 'image/jpg'].include?(content_type)
errors.add_to_base "Image format is not a valid JPEG or PNG."
return false
else
return true
end
end
end
В вашем случае вы можете добавить дополнительный метод, который изменяет расширение на основе этого правильного типа mime (content_type).