after_create 文件保存回调导致间歇性错误

after_create file saving callback resulting in intermittent error

在我的 user 模型中,我有一个 after_create 回调,如下所示:

def set_default_profile_image
  file = Tempfile.new([self.initials, ".jpg"])
  file.binmode
  file.write(Avatarly.generate_avatar(self.full_name, format: "jpg", size: 300))
  begin
    self.profile_image = File.open(file.path)
  ensure
    file.close
    file.unlink
  end
  self.save
end

(self.initials 只是一个 returns 用户首字母的实用方法,因此例如我的个人资料图片将是 "HB.jpg"。)

如果我直接对现有用户调用该方法,它可能会在 80% 的时间内运行。其他时候,它会给我一条错误消息,但我无法在此处重现它(我什至无法在 tmux 中向后滚动足够远以查看它的开头)。错误消息(或者我能看到的,无论如何)包含一个 MIME 类型列表,后面跟着这个位:

content type discovered from file command: application/x-empty. See documentation to allow this combination.

如果我创建一个新用户,回调会在 100% 的时间内产生相同的错误消息。

我的方法使用Avatarly gem生成占位符头像; gem 以 blob 形式生成它们,因此创建了一个 Tempfile 来写入。

我不明白为什么会出现上面的错误。

确保 full_name 具有有效的 return 值并尝试将您的 save 调用移至 begin 部分。您可能正在与保存赛跑并且临时文件为 removed/unlink.

当你这样做时,你期望发生什么?

self.profile_image = File.open(file.path)

没有块,这等同于:

self.profile_image = File.new(file.path)

它们都是return一个文件对象。 profile_image 在数据库中吗?我很确定您发送要持久保存的 File 对象会很生气。如果您想要数据库中该文件的数据,请执行以下操作:

self.profile_image = File.open(file.path).read

如果要保存临时文件的路径:

self.profile_image = File.path(file.path)

如果您正在使用该路径,请记住您正在保存一个临时文件,该文件不会保存很长时间!

我在 an issue on Paperclip's github 中找到了解决方案。我不太了解原因,但似乎这是一个文件系统问题,其中 Tempfile 在读入模型时尚未保存到磁盘。

解决方案是在分配之前对 Tempfile 做任何事情; file.read 工作正常。

def set_default_profile_image
  file = Tempfile.new([self.initials, ".jpg"])
  file.binmode
  file.write(Avatarly.generate_avatar(self.full_name, format: "jpg", size: 300))
  file.read # <-- this fixes the issue
  begin
    self.profile_image = File.open(file.path)
  ensure
    file.close
    file.unlink
  end
  self.save
end