ActiveStorage如何防止重复文件上传;按文件名查找

时间:2019-01-14 22:27:21

标签: ruby-on-rails rails-activestorage

我正在解析电子邮件附件,并将其上传到S3中的ActiveStorage。

我们希望它忽略重复项,但是我看不到通过这些属性进行查询。

class Task < ApplicationRecord
  has_many_attached :documents
end

然后在我的电子邮件Webhook工作中

attachments.each do |attachment|
  tempfile = open(attachment[:url], http_basic_authentication: ["api", ENV.fetch("MAILGUN_API_KEY")])

  # i'd like to do something like this      
  next if task.documents.where(filename: tempfile.filename, bytesize: temfile.bytesize).exist?

  # this is what i'm currently doing
  task.documents.attach(
    io: tempfile,
    filename: attachment[:name],
    content_type: attachment[:content_type]
  )
end

不幸的是,如果有人转发相同的文件,我们就会重复,而且经常重复。

使用当前解决方案进行编辑:

tempfile = open(attachment[:url], http_basic_authentication: ["api", ENV.fetch("MAILGUN_API_KEY")])
md5_digest = Digest::MD5.file(tempfile).base64digest

# if this digest already exists as attached to the file then we're all good.
next if ActiveStorage::Blob.joins(:attachments).where({
    checksum: md5_digest, 
    active_storage_attachments: {name: 'documents', record_type: 'Task', record_id: task.id
  }).exists?

2 个答案:

答案 0 :(得分:1)

Rails利用2个表来存储附件数据; active_storage_attachmentsactive_storage_blobs

active_storage_blobs表中包含上载文件的校验和。 您可以轻松地加入此表以验证文件的存在。

根据@gustavo的回答,我想到了以下内容:

attachments.each do |attachment|
  tempfile = TempFile.new
  tempfile.write open(attachment[:url], http_basic_authentication: ["api", ENV.fetch("MAILGUN_API_KEY")])
  checksum = Digest::MD5.file(tempfile.path).base64digest

  if task.documents.joins(:documents_blobs).exists?(active_storage_blobs: {checksum: checksum})
    tempfile.unlink
    next
  end

  #... Your attachment saving code here
end

注意:请记住在使用该类的类中要求输入'tempfile'

答案 1 :(得分:0)

如果他们仍然更改文件名(这种情况在filename(2).xlsx之类的情况下经常发生),但是内容相同,会发生什么呢?

也许更好的方法是比较校验和?我相信ActiveStorage对象将已经为保存的文件存储了该对象。您可以执行以下操作:

attachments.each do |attachment|
  tempfile = open(attachment[:url], http_basic_authentication: ["api", ENV.fetch("MAILGUN_API_KEY")])
  checksum = Digest::MD5.file(tempfile.path).base64digest

  # i'd like to do something like this      
  next if task.documents.where(checksum: checksum).exist?

  #...
end

这样,无论传入文件名如何,您都知道它是相同的物理文件。