【问题标题】:Reading text from a PDF works in Rails console but not in Rails application从 PDF 读取文本在 Rails 控制台中有效,但在 Rails 应用程序中无效
【发布时间】:2020-10-04 11:40:18
【问题描述】:

我有一个简单的单页可搜索 PDF,它使用 Active Storage 上传到 Rails 6 应用程序模型(汽车)。我可以使用 Rails 控制台中的“tempfile”和“pdf-reader”gem 从 PDF 中提取文本:

> @car.creport.attached?
=> true
> f = Tempfile.new(['file', '.pdf'])
> f.binmode
> f.write(@car.creport.blob.download)
> r = PDF::Reader.new(f.path.to_s)
> r.pages[1].text
=> "Welcome to the ABC Car Report for January 16, 20...

但是,如果我在我的 cars_controller.rb 的 create 方法中尝试同样的事情,它就不起作用:

# cars_controller.rb
...
  def create
    @car = Car.new(car_params)
    @car.filetext = ""
    f = Tempfile.new(['file', '.pdf'])
    f.binmode
    f.write(@car.creport.blob.download)
    r = PDF::Reader.new(f.path.to_s)
    @car.filetext = r.pages[1].text
    ...
  end

当我运行 Rails 应用程序时,我可以创建一个新 Car 并选择要附加的 PDF 文件。但是,当我单击“提交”时,我在 car_controller.rb 的 f.write() 行中收到 FileNotFoundError。

我的直觉是控制器试图读取 blob 以便过早将其写入临时文件(即,在 blob 甚至还没有被写入之前)。我尝试插入 sleep(2) 给它时间,但我得到了相同的 FileNotFoundError。

有什么想法吗?

谢谢!

【问题讨论】:

    标签: ruby-on-rails ruby pdf rails-activestorage pdf-reader


    【解决方案1】:

    我不明白你为什么要跳这么多圈。并且在没有块的情况下使用.download 将整个文件加载到内存中(哎呀)。如果 @car.creport 是一个 ActiveStorage 附件,您可以使用 open method 代替:

    @car.creport.blob.open do |file|
      file.binmode
      r = PDF::Reader.new(file) # just pass the IO object
      @car.filetext = r.pages[1].text
    end if @car.creport
    

    这会将文件转入磁盘(作为临时文件)。

    如果您只是通过普通的旧文件输入进行文件输入,您将在参数中获得ActionDispatch::Http::UploadedFile,这也很容易打开:

    params[:file].open do |file|
      file.binmode
      r = PDF::Reader.new(file) # just pass the IO object
      @car.filetext = r.pages[1].text
    end if params[:file].respond_to?(:open)
    

    【讨论】:

    • 我仍然是一个 n00b,我不确定我在做什么,所以这就是为什么我在那里有这么多步骤......我试图看看它在哪里坏了。我无法让代码的顶部工作。它以相同的“FileNotFoundError”在同一个地方中断。需要明确的是,我有一个表格,用于将 PDF 附件上传到汽车记录。在您的代码块上方,我有:``` def create @car = Car.new(review_params) ``(我不确定为什么此评论的格式不正确?)
    • 事实证明,ActiveStorage 的问题在于细节。在保存父模型之前,附件实际上不可用,这会触发 ActiveStorage blobs 表的更新,该表设置了 resource_id 和 type 列。这会“声明”上传。
    【解决方案2】:

    区别似乎在于您的 @car 变量。

    在控制台中,您附加了一个 blob (@car.creport.attached? => true)。在您的控制器中,您正在初始化 Car 类的一个新实例,因此除非您正在进行一些在后台附加某些东西的初始化,否则它将为零。

    我不确定为什么会返回“找不到文件”错误,但据我所知,这是代码示例之间的唯一区别。您正在尝试编写@car.creport.blob.download,它存在于控制台中的@car,但在您的控制器中为nil。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多