如何访问使用Paperclip / Ruby on Rails上传的文件的原始内容?

31

我正在使用Paperclip / S3进行文件上传。我上传类似文本的文件(不是.txt格式,但它们本质上是.txt)。在显示控制器中,我希望能够获取已上传文件的内容,但不看到“内容”作为其属性之一。在这种情况下我该怎么办?

attachment_file_name: "test.md", attachment_content_type: "application/octet-stream", attachment_file_size: 58, attachment_updated_at: "2011-06-22 01:01:40"

PS - 似乎所有的Paperclip教程都是关于图像而不是文本文件。


1
这个回答应该被采纳为最佳答案。 - theblang
7个回答

102

在 Paperclip 3.0.1 中,您可以使用 io_adapter,它不需要编写额外的文件到本地文件系统中(也不需要从其中删除)。

Paperclip.io_adapters.for(attachment.file).read

我看到实际上这种方法会将以下日志信息写入本地文件系统:[paperclip] 将 uploads/model/documents/1/Image1.jpg 复制到本地文件 /tmp/2fa67f482133f1c934235b73c2a0395420161123-27627-1xc7ieo.jpg - Tensho
@Tensho 看起来对于大多数适配器你是正确的。如果你想避免写入磁盘,你可以使用 StringIOAdapter:https://github.com/thoughtbot/paperclip/blob/master/lib/paperclip/io_adapters/stringio_adapter.rb - jwadsack
@jwadsack,我需要怎么做才能使用StringIOAdapter来替代默认的FileAdapter - atreat
@atreat 我错了,适配器决定数据如何加载。即使是 StringIOAdapter 也会 复制到临时文件。我的原始回答意味着您不应该在 Paperclip 的基础上添加本地文件写入。 - jwadsack
谢谢回复,这正是我在调查中发现的。我选择这条路是因为单个文件写入,然后立即读入内存比管理自己的文件指针更好。 - atreat

6

@jon-m的答案需要更新以反映最新的paperclip更改,为了使其工作,需要将其更改为类似于以下内容:

class Document

  has_attached_file :revision

  def revision_contents(path = 'tmp/tmp.any')
    revision.copy_to_local_file :original, path
    File.open(path).read
  end
end

如@jwadsack所提到的,使用Paperclip.io_adapters.for方法可以完成相同的操作,并且在我看来似乎是更好、更干净的方式。

5

csv_file.path 的返回值不再是文件系统上的有效引用,至少对于本地存储而言。现在它返回根目录之后的路径... 它返回 /class_name/attachment_name/blah/blah 而不是 /rails_root/public/system/class_name/attachment_name/blah/blah。 - Jason
嗯,对于Paperclip 4.3.2中的本地文件系统存储,csv_file.path对我非常有效。 - aec

3

这是我如何访问附件的原始内容:

class Document

  has_attached_file :revision

  def revision_contents
    revision.copy_to_local_file.read
  end

end

请注意,我省略了我的纸夹配置选项和任何类型的错误处理。

8
3.0.1 新增内容:
  • API变更:#to_file已被移除,请使用#copy_to_local_file方法代替。
- RocketR
8
上述的copy_to_local_file并不是那样工作的,因为它需要两个参数,一个是文件样式,一个是本地目标路径。http://rdoc.info/gems/paperclip/Paperclip/Storage/Filesystem:copy_to_local_file - Shaun McDonald
1
@jwadsack 看起来在 API 更改后要好得多。 - John Naegle
2
你可以这样做: copy_to_local_file(nil, 'path_name') style 是用于缩略图的,如果不需要下载缩略图,则可以将其保留为 nil。尽管这有点不被记录在文档中。 - Rich

1

在展示文件内容之前,您需要将文件的内容(使用Ruby的File.open)加载到变量中。如果您的应用程序得到了大量使用,这可能是一个昂贵的操作,因此在上传后阅读文件内容并将其放入数据库中的文本列中可能是值得的。


1

1
这是我用于将 Paperclip 中的文件上传到 Active Storage 的方法,并提供了一些关于在内存中暂时处理文件的指导。注意:这只适用于相对较小的文件。
写于 gem paperclip 6.1.0 当我有一个简单的模型时,此方法适用。
class Post
  has_attached_file :image
end

在 Ruby 中使用临时文件,这样我们就不必担心关闭文件。
  Tempfile.create do |tmp_file|
    post.image.copy_to_local_file(nil, tmp_file.path)

    post.image_temp.attach(
      io: tmp_file,
      filename: post.image_file_name,
      content_type: post.image_content_type
    )
  end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接