Carrierwave 将 mime 类型设置为 invalid/invalid

Carrierwave sets mime type to invalid/invalid

我最近从 Carrierwave 1.3 升级到 2.1,由于无效的 MIME 类型,我有几个规范失败了。

我存储在数据库中,CSV 上传,如果 mime 类型是 text/csv,我在模型上验证。

validates :file, presence: true, file_content_type: {
    allow: [
      'text/csv',
      'application/vnd.ms-excel',
      'application/vnd.ms-office',
      'application/octet-stream',
      'text/comma-separated-values'
    ]
  }

根据规范,我创建了一个夹具

let(:file) { fixture_file_upload('files/fixture.csv', 'text/csv') }

当我调试时,

@file=
  #<CarrierWave::SanitizedFile:0x00007f8c731791f0
   @content=nil,
   @content_type="invalid/invalid",
   @file="/Users/tiagovieira/code/work/tpc/public/uploads/csv_file_upload/file/1/1605532759-308056149220914-0040-7268/fixture.csv",
   @original_filename="fixture.csv">,
 @filename="fixture.csv",
 @identifier="fixture.csv",

这是否与 carrierwave 停止使用 mime-types gem 作为依赖项有关?

使用Rack::Test::UploadedFile

为安装的模型分配一个 Rack::Test::UploadedFile 对象 假设您的模型是:

class User < ApplicationRecord
  mount_uploader :file, FileUploader
end

要测试上传器,您可以使用类似的东西:

user.file = Rack::Test::UploadedFile.new(File.open('test_file.csv'), "text/csv")
user.save

Carrierwave 的 content_type_whitelist 或 extension_whitelist

的白名单
class FileUploader < CarrierWave::Uploader::Base

  private

  def extension_whitelist
    %w(csv xlsx xls)
  end

  def content_type_whitelist
    [
      'text/csv',
      'application/vnd.ms-excel',
      'application/vnd.ms-office',
      'application/octet-stream',
      'text/comma-separated-values'
    ]
  end
end

同时检查: https://til.codes/testing-carrierwave-file-uploads-with-rspec-and-factorygirl/

看来问题找到了。

在之前的carrierwave版本中“CarrierWave::SanitizedFile”content_type是通过扩展计算的 https://github.com/carrierwaveuploader/carrierwave/blob/1.x-stable/lib/carrierwave/sanitized_file.rb

    def content_type
      return @content_type if @content_type
      if @file.respond_to?(:content_type) and @file.content_type
        @content_type = @file.content_type.to_s.chomp
      elsif path
        @content_type = ::MIME::Types.type_for(path).first.to_s
      end
    end

而且现在有更复杂的方式。它使用算法根据此文件包含的数据来识别文件类型。

https://github.com/carrierwaveuploader/carrierwave/blob/master/lib/carrierwave/sanitized_file.rb

    def content_type
      @content_type ||=
        existing_content_type ||
        mime_magic_content_type ||
        mini_mime_content_type
    end

我在 mime_magic_content_type 之后有“invalid/invalid”内容类型,似乎无法使用“MimeMagic.by_magic”获取文件类型。

PS 我看到通常的 css 文件返回“plain/text”content_type。 https://github.com/minad/mimemagic/blob/master/lib/mimemagic/tables.rb#L1506