7

在 Rails 中创建对象时,我想自动为它分配资产目录中的库存图像,以后可以由用户覆盖。

结果,我在创建对象时执行以下私有方法:

def save_stock_image
  image_path = Dir.glob(<list-of-images-from-directory>).sample

  File.open(image_path) do |file|
    self.image = file
    self.save!
  end
end

但是,经过 6 次 RSpec 测试后,我开始收到以下错误:

Failure/Error: let(:object) { create(:object) }
Errno::EMFILE:
  Too many open files - /tmp/16020130822-36578-q8j9v9.jpg
# ./app/models/object.rb:502:in `block in save_stock_image'
# ./app/models/object.rb:501:in `open'
# ./app/models/object.rb:501:in `save_stock_image'
# ./spec/controllers/object_controller_spec.rb:318:in `block (3 levels) in <top (required)>'
# ./spec/controllers/object_controller_spec.rb:344:in `block (4 levels) in <top (required)>'

上述错误出现在 60 次测试中的 40 次左右。我查看了一些 SO 问题,以及https://github.com/thoughtbot/paperclip/issues/1122https://github.com/thoughtbot/paperclip/issues/1000。我能找到的最接近的答案是确保文件描述符正在关闭。在我File.open在块中使用之前,我明确地关闭了文件file.close- 这也不起作用。

有什么明显的我做错了吗?有没有更好的方法来完成我想要做的事情?

更新

看起来它与 Paperclip 在上传到 S3 之前创建的临时文件有关。关闭那些我丢失的临时文件有什么问题吗?

4

3 回答 3

1

我自己也遇到了这个。看起来主分支有一个修复。在这里查看我的评论:

https://github.com/thoughtbot/paperclip/issues/1326?source=cc

于 2013-12-04T20:42:52.773 回答
0

刚遇到这个,最新的代码对我没有帮助。因此,我通过生成子进程将关闭这些临时文件的工作委托给操作系统:

def save_stock_image
  ActiveRecord::Base.connection.disconnect!
  Proces.fork do 
    image_path = Dir.glob(<list-of-images-from-directory>).sample

    File.open(image_path) do |file|
      self.image = file
      self.save!
    end
  end
  Process.wait    
  ActiveRecord::Base.establish_connection
end

另外,考虑在 Process.wait 上设置超时,如下所示:Waiting for Ruby child pid to exit

于 2015-03-14T03:26:03.763 回答
0

如果这是一个开发/测试环境,并且您想要快速解决。

尝试识别 resque 进程 ID,将其杀死并重新启动 resque 服务器。

此外,您可以尝试以下

Redis.current.client.reconnect
$redis = Redis.current
于 2014-11-25T08:01:02.587 回答