【问题标题】:Rails 4: Tempfile.read returns no data on second callRails 4:Tempfile.read 在第二次调用时不返回数据
【发布时间】:2014-10-13 16:18:40
【问题描述】:

我使用before_validation 回调来保存来自文件输入的数据。

def attach_document
  if id_document_file
    self.id_document = Document.create(:binary_data => id_document_file.read, :filetype => id_document_file.content_type, :filename => id_document_file.original_file, :filesize => id_document_file.size)
  end
end

id_document_file 通过attr_accessor 定义并由控制器提供。问题是before_validation 有时会被调用两次。第一次一切都按预期工作。但在第二次调用时,read 方法不返回任何数据。奇怪的是,content_typeoriginal_filesize 返回正确的值。

第二次调用的 SQL 如下所示:

SQL (1.2ms)  INSERT INTO "documents" ("binary_data", "created_at", "filename", "filesize", "filetype", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"  [["binary_data", "<0 bytes of binary data>"], ["created_at", Mon, 13 Oct 2014 16:39:57 CEST +02:00], ["filename", "sample.pdf"], ["filesize", 236991], ["filetype", "application/pdf"], ["updated_at", Mon, 13 Oct 2014 16:39:57 CEST +02:00]]

我正在考虑使用文件大小作为解决方法 (if id_document_file.size == 0) 来停止代码执行,但这显然不起作用,因为 size 方法返回正确的文件大小。但主要问题是:为什么第二次调用没有返回任何数据?

更新:

值得注意的是,我从两个不同的控制器中保存了模型。一个是users 控制器,另一个是addresses 控制器。模型之间的关系如下:

用户

has_one :address

地址

belongs_to :user
belongs_to :id_document, :class_name => 'Document'

当我从地址控制器调用@address.save 时,回调被调用一次。但是,如果我从用户控制器调用@user.save(之前使用@user.build_address(user_params[:address_attributes])),则回调会被调用两次。

上述回调在“地址”模型中。

【问题讨论】:

    标签: ruby-on-rails file-upload temporary-files


    【解决方案1】:

    这里发生的情况是,您也使用持久性调用触发了 before_validate,因此为什么会调用它两次

    以下内容也会第二次触发回调:

    self.id_document = Document.create(:binary_data => id_document_file.read, :filetype => id_document_file.content_type, :filename => id_document_file.original_file, :filesize => id_document_file.size)
    

    我还假设因为您可能在同一个调用堆栈中,所以该文件上有一个锁(因为它仍然被第一次调用 file.read 所持有?)

    我会尝试阻止这种重复的无意行为,因为这看起来是您现在的问题。

    如果你真的想深挖,看看是不是这样,请参考下面的SO帖子:

    How can I check if a file is being used by other application?

    【讨论】:

    • 我更新了我的问题以反映我的模型和控制器。我认为 Document.create 不会触发 Address 模型中的回调。如果是这种情况,则必须始终触发回调两次。但是当我调用@address.save 时它不是。
    猜你喜欢
    • 2010-11-29
    • 2020-10-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 2020-04-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多