ActiveStorage CSV 文件强制编码?

问题描述 投票:0回答:3

我正在上传一个 CSV 文件,该文件在将行导入数据库时遇到问题:

Encoding::UndefinedConversionError ("\xCC" from ASCII-8BIT to UTF-8)

确保每列正确编码以放入数据库忽略的最有效方法是什么?

最基本的方法是遍历每一行和每个字段并强制对字符串进行编码,但这似乎效率非常低。有什么更好的方法来处理这个问题?

目前它只是作为参数上传(

:csv_file
)。然后我按如下方式访问它:

CSV.parse(csv_file.download)
在模型内。

我假设在 activestorage 文件上调用 CSV.parse 时有一种方法可以强制编码,但不确定如何实现。有任何想法吗?

谢谢!

ruby-on-rails ruby ruby-on-rails-5 rails-activestorage
3个回答
5
投票

最新版本的 ActiveStorage (6.0.0.rc1) 添加了一个 API,能够将文件下载到临时文件,然后您可以从中读取。我假设 Ruby 将使用正确的编码从文件中读取。

https://edgeguides.rubyonrails.org/active_storage_overview.html#downloading-files

如果您不想升级到 Rails 6 的 RC(就像我一样),您可以使用此方法将字符串转换为 UTF-8,同时消除文件中可能存在的字节顺序标记:

wrongly_encoded_string = active_record_model.attachment.download
correctly_encoded_string = wrongly_encoded_string.bytes.pack("c*").force_encoding("UTF-8")

0
投票

2023 年回来赞扬@eric-parshall 的回答。我的应用程序将完整的电子邮件正文(通常是原始 html)存储为 ActiveStorage 文件附件,并且在使用

.download
拉动这些正文以呈现它们时遇到了相当长的问题。 ruby 处理编码的方式始终意味着主体以
ASCII-8BIT
的编码进入,强制返回编码仍然会偶尔出现错误。

虽然 Eric 几年前在 Rails 6 上线之前就提到过这一点,但这个解决方案(以及不知何故的链接🤣)仍然非常有效。这是 Rails 7.1 文档的版本化链接,以防 Eric 的链接失效:

https://guides.rubyonrails.org/v7.1/active_storage_overview.html#downloading-files

埃里克提出的想法是完全正确的。如果您使用

.open
API 将附件保存到临时文件,然后使用
File.read
,您的编码问题可能会消失。看起来像这样:

eml = Email.last
eml.update!(
  full_body: {
    io: StringIO.new("This is a test!"),
    filename: "full_body_test.html",
    content_type: "text/plain"
  }
) 

# Before, using `#download`

content = eml.full_body.download
content.encoding #=> #<Encoding:ASCII-8BIT>

# After, using `#open`

content = nil
Email.last.full_body.open do |file|
  content = File.read file
end
content.encoding #=> #<Encoding:UTF-8>

0
投票

根据@JonSullivan的回答,我想添加以下内容来附加/上传文件,

 file = params[:csv_import]

    blob = ActiveStorage::Blob.create_and_upload!(
      io: file,
      filename: file.original_filename,
      content_type: file.content_type
    )

然后您可以使用 activestorage key 读取文件:

file_path    = ActiveStorage::Blob.service.path_for(blob.key)
file         = File.open(file_path, 'r')

      CSV.foreach(file_path, headers: true, col_sep: ";") do |row|
        puts row["fullname"]
        puts row["id"]
      end
      ensure
        file.close
      end

问题就解决了,无需进行编码杂技。

© www.soinside.com 2019 - 2024. All rights reserved.